2 * Copyright (c) 2015 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>
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-abstraction/font-client-helper.h>
28 #include <platform-abstractions/portable/image-operations.h>
29 #include <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;
47 const std::string FONT_FORMAT( "TrueType" );
48 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
49 const int DEFAULT_FONT_WIDTH = 100; // normal
50 const int DEFAULT_FONT_WEIGHT = 80; // normal
51 const int DEFAULT_FONT_SLANT = 0; // normal
53 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
55 const bool FONT_FIXED_SIZE_BITMAP( true );
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 );
101 namespace TextAbstraction
108 * @brief Returns the FontWidth's enum index for the given width value.
110 * @param[in] width The width value.
112 * @return The FontWidth's enum index.
114 FontWidth::Type IntToWidthType( int width )
116 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
120 * @brief Returns the FontWeight's enum index for the given weight value.
122 * @param[in] weight The weight value.
124 * @return The FontWeight's enum index.
126 FontWeight::Type IntToWeightType( int weight )
128 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
132 * @brief Returns the FontSlant's enum index for the given slant value.
134 * @param[in] slant The slant value.
136 * @return The FontSlant's enum index.
138 FontSlant::Type IntToSlantType( int slant )
140 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
143 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list )
144 : fontDescription( font ),
145 fallbackFonts( list )
149 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
150 FontDescriptionId index )
151 : fontDescription( fontDescription ),
156 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
157 PointSize26Dot6 requestedPointSize,
159 : validatedFontId( validatedFontId ),
160 requestedPointSize( requestedPointSize ),
165 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
166 const FontPath& path,
167 PointSize26Dot6 requestedPointSize,
169 const FontMetrics& metrics )
170 : mFreeTypeFace( ftFace ),
172 mRequestedPointSize( requestedPointSize ),
175 mFixedWidthPixels( 0.0f ),
176 mFixedHeightPixels( 0.0f ),
178 mIsFixedSizeBitmap( false )
182 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
183 const FontPath& path,
184 PointSize26Dot6 requestedPointSize,
186 const FontMetrics& metrics,
189 : mFreeTypeFace( ftFace ),
191 mRequestedPointSize( requestedPointSize ),
194 mFixedWidthPixels( fixedWidth ),
195 mFixedHeightPixels( fixedHeight ),
197 mIsFixedSizeBitmap( true )
201 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
202 unsigned int verticalDpi )
203 : mFreeTypeLibrary( NULL ),
204 mDpiHorizontal( horizontalDpi ),
205 mDpiVertical( verticalDpi ),
206 mDefaultFontDescription(),
210 mValidatedFontCache(),
211 mFontDescriptionCache( 1u ),
213 mVectorFontCache( NULL ),
215 mDefaultFontDescriptionCached( false )
217 int error = FT_Init_FreeType( &mFreeTypeLibrary );
218 if( FT_Err_Ok != error )
220 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
223 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
224 mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
228 FontClient::Plugin::~Plugin()
230 for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
234 FallbackCacheItem& item = *it;
236 if( item.fallbackFonts )
238 delete item.fallbackFonts;
239 item.fallbackFonts = NULL;
243 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
244 delete mVectorFontCache;
247 FT_Done_FreeType( mFreeTypeLibrary );
250 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
251 unsigned int verticalDpi )
253 mDpiHorizontal = horizontalDpi;
254 mDpiVertical = verticalDpi;
257 void FontClient::Plugin::ResetSystemDefaults()
259 mDefaultFontDescriptionCached = false;
262 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList )
264 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() );
268 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
270 FcResult result = FcResultMatch;
272 // Match the pattern.
273 FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
275 false /* don't trim */,
279 if( NULL != fontSet )
281 // Reserve some space to avoid reallocations.
282 fontList.reserve( fontSet->nfont );
284 for( int i = 0u; i < fontSet->nfont; ++i )
286 FcPattern* fontPattern = fontSet->fonts[i];
290 // Skip fonts with no path
291 if( GetFcString( fontPattern, FC_FILE, path ) )
293 fontList.push_back( FontDescription() );
294 FontDescription& newFontDescription = fontList.back();
296 newFontDescription.path = path;
301 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
302 GetFcInt( fontPattern, FC_WIDTH, width );
303 GetFcInt( fontPattern, FC_WEIGHT, weight );
304 GetFcInt( fontPattern, FC_SLANT, slant );
305 newFontDescription.width = IntToWidthType( width );
306 newFontDescription.weight = IntToWeightType( weight );
307 newFontDescription.slant = IntToSlantType( slant );
311 FcFontSetDestroy( fontSet );
314 FcPatternDestroy( fontFamilyPattern );
317 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
319 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
321 if( mDefaultFonts.empty() )
323 FontDescription fontDescription;
324 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
325 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
326 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
327 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
328 SetFontList( fontDescription, mDefaultFonts );
331 defaultFonts = mDefaultFonts;
334 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
336 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
338 if( !mDefaultFontDescriptionCached )
340 FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
342 FcPattern* matchPattern = FcPatternCreate();
343 FcConfigSubstitute(NULL, matchPattern, FcMatchPattern);
344 FcDefaultSubstitute( matchPattern );
346 MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription );
347 FcPatternDestroy( matchPattern );
349 mDefaultFontDescriptionCached = true;
352 fontDescription.path = mDefaultFontDescription.path;
353 fontDescription.family = mDefaultFontDescription.family;
354 fontDescription.width = mDefaultFontDescription.width;
355 fontDescription.weight = mDefaultFontDescription.weight;
356 fontDescription.slant = mDefaultFontDescription.slant;
359 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
361 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
363 if( mSystemFonts.empty() )
368 systemFonts = mSystemFonts;
371 void FontClient::Plugin::GetDescription( FontId id,
372 FontDescription& fontDescription ) const
374 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
375 endIt = mFontIdCache.end();
379 const FontIdCacheItem& item = *it;
381 if( item.fontId == id )
383 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
388 DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
391 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
393 const FontId index = id - 1u;
396 index < mFontCache.size() )
398 return ( *( mFontCache.begin() + index ) ).mRequestedPointSize;
402 DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
405 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
408 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
410 PointSize26Dot6 requestedPointSize,
413 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFontForCharacter\n");
416 bool foundColor = false;
418 // Traverse the list of fonts.
419 // Check for each font if supports the character.
420 for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end();
424 const FontDescription& description = *it;
426 FcPattern* pattern = CreateFontFamilyPattern( description );
428 FcResult result = FcResultMatch;
429 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
431 FcCharSet* charSet = NULL;
432 FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
434 if( FcCharSetHasChar( charSet, charcode ) )
436 Vector< PointSize26Dot6 > fixedSizes;
437 GetFixedSizes( description,
440 PointSize26Dot6 actualPointSize = requestedPointSize;
442 const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
446 // If the font is not scalable, pick the largest size <= requestedPointSize
447 actualPointSize = fixedSizes[0];
448 for( unsigned int i=1; i<count; ++i )
450 if( fixedSizes[i] <= requestedPointSize &&
451 fixedSizes[i] > actualPointSize )
453 actualPointSize = fixedSizes[i];
458 fontId = GetFontId( description,
465 foundColor = IsColorGlyph( fontId, GetGlyphIndex( fontId, charcode ) );
468 // Keep going unless we prefer a different (color) font.
469 if( !preferColor || foundColor )
471 FcPatternDestroy( match );
472 FcPatternDestroy( pattern );
477 FcPatternDestroy( match );
478 FcPatternDestroy( pattern );
484 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
485 PointSize26Dot6 requestedPointSize,
488 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
492 // Create the list of default fonts if it has not been created.
493 if( mDefaultFonts.empty() )
495 FontDescription fontDescription;
496 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
497 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
498 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
499 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
501 SetFontList( fontDescription, mDefaultFonts );
504 // Traverse the list of default fonts.
505 // Check for each default font if supports the character.
506 fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedPointSize, preferColor );
511 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
512 const FontDescription& preferredFontDescription,
513 PointSize26Dot6 requestedPointSize,
516 // The font id to be returned.
519 FontDescription fontDescription;
521 // Fill the font description with the preferred font description and complete with the defaults.
522 fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
523 fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
524 fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
525 fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
527 // Check first if the font's description has been queried before.
528 FontList* fontList( NULL );
530 if( !FindFallbackFontList( fontDescription, fontList ) )
532 fontList = new FontList;
533 SetFontList( fontDescription, *fontList );
535 // Add the font-list to the cache.
536 mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList ) );
541 fontId = FindFontForCharacter( *fontList, charcode, requestedPointSize, preferColor );
547 FontId FontClient::Plugin::GetFontId( const FontPath& path,
548 PointSize26Dot6 requestedPointSize,
549 PointSize26Dot6 actualPointSize,
551 bool cacheDescription )
553 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
557 if( NULL != mFreeTypeLibrary )
560 if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
566 id = CreateFont( path, requestedPointSize, actualPointSize, faceIndex, cacheDescription );
573 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
574 PointSize26Dot6 requestedPointSize,
575 PointSize26Dot6 actualPointSize,
576 FaceIndex faceIndex )
578 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() );
580 // This method uses three vectors which caches:
581 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
582 // * The path to font file names.
583 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
585 // 1) Checks in the cache if the font's description has been validated before.
586 // If it was it gets an index to the vector with paths to font file names. Otherwise,
587 // retrieves using font config a path to a font file name which matches with the
588 // font's description. The path is stored in the cache.
590 // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
591 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
592 // the GetFontId() method with the path to the font file name and the point size to
595 // The font id to be returned.
598 // Check first if the font's description have been validated before.
599 FontDescriptionId validatedFontId = 0u;
601 if( !FindValidatedFont( fontDescription,
604 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n");
606 // Use font config to validate the font's description.
607 ValidateFont( fontDescription,
611 // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
612 if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
614 // Retrieve the font file name path.
615 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
617 // Retrieve the font id. Do not cache the description as it has been already cached.
618 fontId = GetFontId( description.path,
624 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
625 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
633 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
634 FontDescriptionId& validatedFontId )
636 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
638 // Create a font pattern.
639 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
641 FontDescription description;
643 bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description );
644 FcPatternDestroy( fontFamilyPattern );
648 // Set the index to the vector of paths to font file names.
649 validatedFontId = mFontDescriptionCache.size();
651 // Add the path to the cache.
652 mFontDescriptionCache.push_back( description );
654 // Cache the index and the matched font's description.
655 FontDescriptionCacheItem item( description,
658 mValidatedFontCache.push_back( item );
660 if( ( fontDescription.family != description.family ) ||
661 ( fontDescription.width != description.width ) ||
662 ( fontDescription.weight != description.weight ) ||
663 ( fontDescription.slant != description.slant ) )
665 // Cache the given font's description if it's different than the matched.
666 FontDescriptionCacheItem item( fontDescription,
669 mValidatedFontCache.push_back( item );
674 DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
675 fontDescription.family.c_str(),
676 fontDescription.width,
677 fontDescription.weight,
678 fontDescription.slant );
681 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() );
684 void FontClient::Plugin::GetFontMetrics( FontId fontId,
685 FontMetrics& metrics )
687 if( ( fontId > 0 ) &&
688 ( fontId - 1u < mFontCache.size() ) )
690 const FontFaceCacheItem& font = mFontCache[fontId-1];
692 metrics = font.mMetrics;
694 // Adjust the metrics if the fixed-size font should be down-scaled
695 if( font.mIsFixedSizeBitmap )
697 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
699 if( desiredFixedSize > 0.f )
701 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
703 metrics.ascender = floorf( metrics.ascender * scaleFactor );
704 metrics.descender = floorf( metrics.descender * scaleFactor );
705 metrics.height = floorf( metrics.height * scaleFactor );
706 metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
707 metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
713 DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
717 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
720 GlyphIndex index( 0 );
723 fontId-1 < mFontCache.size() )
725 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
727 index = FT_Get_Char_Index( ftFace, charcode );
733 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
738 if( VECTOR_GLYPH == type )
740 return GetVectorMetrics( array, size, horizontal );
743 return GetBitmapMetrics( array, size, horizontal );
746 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
750 bool success( true );
752 for( unsigned int i=0; i<size; ++i )
754 GlyphInfo& glyph = array[i];
756 FontId fontId = glyph.fontId;
759 fontId-1 < mFontCache.size() )
761 const FontFaceCacheItem& font = mFontCache[fontId-1];
763 FT_Face ftFace = font.mFreeTypeFace;
765 #ifdef FREETYPE_BITMAP_SUPPORT
766 // Check to see if we should be loading a Fixed Size bitmap?
767 if ( font.mIsFixedSizeBitmap )
769 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
770 if ( FT_Err_Ok == error )
772 glyph.width = font.mFixedWidthPixels;
773 glyph.height = font.mFixedHeightPixels;
774 glyph.advance = font.mFixedWidthPixels;
775 glyph.xBearing = 0.0f;
776 glyph.yBearing = font.mFixedHeightPixels;
778 // Adjust the metrics if the fixed-size font should be down-scaled
779 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
781 if( desiredFixedSize > 0.f )
783 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
785 glyph.width = floorf( glyph.width * scaleFactor );
786 glyph.height = floorf( glyph.height * scaleFactor );
787 glyph.advance = floorf( glyph.advance * scaleFactor );
788 glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
789 glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
791 glyph.scaleFactor = scaleFactor;
796 DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
803 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_DEFAULT );
805 if( FT_Err_Ok == error )
807 glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
808 glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
811 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
812 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
816 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
817 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
835 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
839 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
840 bool success( true );
842 for( unsigned int i=0; i<size; ++i )
844 FontId fontId = array[i].fontId;
847 fontId-1 < mFontCache.size() )
849 FontFaceCacheItem& font = mFontCache[fontId-1];
851 if( ! font.mVectorFontId )
853 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
856 mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
858 // Vector metrics are in EMs, convert to pixels
859 const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
860 array[i].width *= scale;
861 array[i].height *= scale;
862 array[i].xBearing *= scale;
863 array[i].yBearing *= scale;
864 array[i].advance *= scale;
878 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data )
880 if( ( fontId > 0 ) &&
881 ( fontId - 1u < mFontCache.size() ) )
883 FT_Face ftFace = mFontCache[fontId - 1u].mFreeTypeFace;
887 #ifdef FREETYPE_BITMAP_SUPPORT
888 // Check to see if this is fixed size bitmap
889 if ( mFontCache[fontId - 1u].mIsFixedSizeBitmap )
891 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
896 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
898 if( FT_Err_Ok == error )
901 error = FT_Get_Glyph( ftFace->glyph, &glyph );
903 // Convert to bitmap if necessary
904 if ( FT_Err_Ok == error )
906 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
908 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
909 if ( FT_Err_Ok == error )
911 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
912 ConvertBitmap( data, bitmapGlyph->bitmap );
916 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
921 ConvertBitmap( data, ftFace->glyph->bitmap );
924 // Created FT_Glyph object must be released with FT_Done_Glyph
925 FT_Done_Glyph( glyph );
930 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
935 PixelData FontClient::Plugin::CreateBitmap( FontId fontId,
936 GlyphIndex glyphIndex )
938 TextAbstraction::FontClient::GlyphBufferData data;
940 CreateBitmap( fontId, glyphIndex, data );
942 return PixelData::New( data.buffer,
943 data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
947 PixelData::DELETE_ARRAY );
950 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
955 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
957 fontId-1 < mFontCache.size() )
959 FontFaceCacheItem& font = mFontCache[fontId-1];
961 if( ! font.mVectorFontId )
963 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
966 mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
971 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
973 // First look into the cache if there is an ellipsis glyph for the requested point size.
974 for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
975 endIt = mEllipsisCache.End();
979 const EllipsisItem& item = *it;
981 if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
983 // Use the glyph in the cache.
988 // No glyph has been found. Create one.
989 mEllipsisCache.PushBack( EllipsisItem() );
990 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
992 item.requestedPointSize = requestedPointSize;
994 // Find a font for the ellipsis glyph.
995 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
999 // Set the character index to access the glyph inside the font.
1000 item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
1001 ELLIPSIS_CHARACTER );
1003 GetBitmapMetrics( &item.glyph, 1u, true );
1008 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1010 FT_Error error = -1;
1012 #ifdef FREETYPE_BITMAP_SUPPORT
1013 if( ( fontId > 0 ) &&
1014 ( fontId - 1u < mFontCache.size() ) )
1016 const FontFaceCacheItem& item = mFontCache[fontId - 1u];
1017 FT_Face ftFace = item.mFreeTypeFace;
1019 // Check to see if this is fixed size bitmap
1020 if( item.mIsFixedSizeBitmap )
1022 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1027 return FT_Err_Ok == error;
1030 void FontClient::Plugin::InitSystemFonts()
1032 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
1034 FcFontSet* fontSet = GetFcFontSet();
1038 // Reserve some space to avoid reallocations.
1039 mSystemFonts.reserve( fontSet->nfont );
1041 for( int i = 0u; i < fontSet->nfont; ++i )
1043 FcPattern* fontPattern = fontSet->fonts[i];
1047 // Skip fonts with no path
1048 if( GetFcString( fontPattern, FC_FILE, path ) )
1050 mSystemFonts.push_back( FontDescription() );
1051 FontDescription& fontDescription = mSystemFonts.back();
1053 fontDescription.path = path;
1058 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1059 GetFcInt( fontPattern, FC_WIDTH, width );
1060 GetFcInt( fontPattern, FC_WEIGHT, weight );
1061 GetFcInt( fontPattern, FC_SLANT, slant );
1062 fontDescription.width = IntToWidthType( width );
1063 fontDescription.weight = IntToWeightType( weight );
1064 fontDescription.slant = IntToSlantType( slant );
1065 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
1070 FcFontSetDestroy( fontSet );
1074 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription )
1076 FcResult result = FcResultMatch;
1077 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1086 GetFcString( match, FC_FILE, fontDescription.path );
1087 GetFcString( match, FC_FAMILY, fontDescription.family );
1088 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str());
1089 GetFcInt( match, FC_WIDTH, width );
1090 GetFcInt( match, FC_WEIGHT, weight );
1091 GetFcInt( match, FC_SLANT, slant );
1092 fontDescription.width = IntToWidthType( width );
1093 fontDescription.weight = IntToWeightType( weight );
1094 fontDescription.slant = IntToSlantType( slant );
1096 // destroyed the matched pattern
1097 FcPatternDestroy( match );
1104 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
1106 // create the cached font family lookup pattern
1107 // a pattern holds a set of names, each name refers to a property of the font
1108 FcPattern* fontFamilyPattern = FcPatternCreate();
1110 if( !fontFamilyPattern )
1115 // add a property to the pattern for the font family
1116 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1118 int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1122 width = DEFAULT_FONT_WIDTH;
1125 int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1129 weight = DEFAULT_FONT_WEIGHT;
1132 int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1136 slant = DEFAULT_FONT_SLANT;
1139 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1140 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1141 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1143 // Add a property of the pattern, to say we want to match TrueType fonts
1144 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1146 // modify the config, with the mFontFamilyPatterm
1147 FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1149 // provide default values for unspecified properties in the font pattern
1150 // e.g. patterns without a specified style or weight are set to Medium
1151 FcDefaultSubstitute( fontFamilyPattern );
1153 return fontFamilyPattern;
1156 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1158 // create a new pattern.
1159 // a pattern holds a set of names, each name refers to a property of the font
1160 FcPattern* pattern = FcPatternCreate();
1162 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1163 FcObjectSet* objectSet = FcObjectSetCreate();
1165 // build an object set from a list of property names
1166 FcObjectSetAdd( objectSet, FC_FILE );
1167 FcObjectSetAdd( objectSet, FC_FAMILY );
1168 FcObjectSetAdd( objectSet, FC_WIDTH );
1169 FcObjectSetAdd( objectSet, FC_WEIGHT );
1170 FcObjectSetAdd( objectSet, FC_SLANT );
1172 // get a list of fonts
1173 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1174 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1176 // clear up the object set
1179 FcObjectSetDestroy( objectSet );
1181 // clear up the pattern
1184 FcPatternDestroy( pattern );
1190 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1191 const char* const n,
1192 std::string& string )
1194 FcChar8* file = NULL;
1195 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1197 if( FcResultMatch == retVal )
1199 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1200 string.assign( reinterpret_cast<const char*>( file ) );
1208 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1210 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1212 if( FcResultMatch == retVal )
1220 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1221 PointSize26Dot6 requestedPointSize,
1222 PointSize26Dot6 actualPointSize,
1223 FaceIndex faceIndex,
1224 bool cacheDescription )
1228 // Create & cache new font face
1230 int error = FT_New_Face( mFreeTypeLibrary,
1235 if( FT_Err_Ok == error )
1237 // Check to see if the font contains fixed sizes?
1238 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1240 // Ensure this size is available
1241 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1243 if ( static_cast<FT_Pos>( actualPointSize ) == ftFace->available_sizes[ i ].size )
1245 // Tell Freetype to use this size
1246 error = FT_Select_Size( ftFace, i );
1247 if ( FT_Err_Ok != error )
1249 DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1253 float fixedWidth = static_cast< float >( ftFace->available_sizes[ i ].width );
1254 float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1256 // Indicate that the font is a fixed sized bitmap
1257 FontMetrics metrics( fixedHeight, // The ascender in pixels.
1259 fixedHeight, // The height in pixels.
1263 mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1264 id = mFontCache.size();
1266 if( cacheDescription )
1268 CacheFontPath( ftFace, id, requestedPointSize, path );
1276 // Can't find this size
1277 std::stringstream sizes;
1278 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1284 sizes << ftFace->available_sizes[ i ].size;
1286 DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1287 path.c_str(), actualPointSize, sizes.str().c_str() );
1291 error = FT_Set_Char_Size( ftFace,
1297 if( FT_Err_Ok == error )
1300 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1302 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1303 static_cast< float >( ftMetrics.descender ) * FROM_266,
1304 static_cast< float >( ftMetrics.height ) * FROM_266,
1305 static_cast< float >( ftFace->underline_position ) * FROM_266,
1306 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1308 mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1309 id = mFontCache.size();
1311 if( cacheDescription )
1313 CacheFontPath( ftFace, id, requestedPointSize, path );
1318 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, actualPointSize );
1324 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1330 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1332 if( srcBitmap.width*srcBitmap.rows > 0 )
1334 switch( srcBitmap.pixel_mode )
1336 case FT_PIXEL_MODE_GRAY:
1338 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1340 const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1341 data.buffer = new unsigned char[bufferSize];
1342 data.width = srcBitmap.width;
1343 data.height = srcBitmap.rows;
1344 data.format = Pixel::L8;
1345 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1350 #ifdef FREETYPE_BITMAP_SUPPORT
1351 case FT_PIXEL_MODE_BGRA:
1353 if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1355 // Set the input dimensions.
1356 const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1358 // Set the output dimensions.
1359 // If the output dimension is not given, the input dimension is set
1360 // and won't be downscaling.
1361 data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1362 data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1363 const ImageDimensions desiredDimensions( data.width, data.height );
1365 // Creates the output buffer
1366 const unsigned int bufferSize = data.width * data.height * 4u;
1367 data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1369 if( inputDimensions == desiredDimensions )
1371 // There isn't downscaling.
1372 memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1376 Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1379 desiredDimensions );
1381 data.format = Pixel::BGRA8888;
1388 DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1395 bool FontClient::Plugin::FindFont( const FontPath& path,
1396 PointSize26Dot6 requestedPointSize,
1397 FaceIndex faceIndex,
1398 FontId& fontId ) const
1401 for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1402 endIt = mFontCache.end();
1406 const FontFaceCacheItem& cacheItem = *it;
1408 if( cacheItem.mRequestedPointSize == requestedPointSize &&
1409 cacheItem.mFaceIndex == faceIndex &&
1410 cacheItem.mPath == path )
1420 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1421 FontDescriptionId& validatedFontId )
1423 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1425 validatedFontId = 0u;
1427 for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1428 endIt = mValidatedFontCache.end();
1432 const FontDescriptionCacheItem& item = *it;
1434 if( !fontDescription.family.empty() &&
1435 ( fontDescription.family == item.fontDescription.family ) &&
1436 ( fontDescription.width == item.fontDescription.width ) &&
1437 ( fontDescription.weight == item.fontDescription.weight ) &&
1438 ( fontDescription.slant == item.fontDescription.slant ) )
1440 validatedFontId = item.index;
1442 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1448 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1453 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1454 FontList*& fontList )
1456 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1460 for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1464 const FallbackCacheItem& item = *it;
1466 if( !fontDescription.family.empty() &&
1467 ( fontDescription.family == item.fontDescription.family ) &&
1468 ( fontDescription.width == item.fontDescription.width ) &&
1469 ( fontDescription.weight == item.fontDescription.weight ) &&
1470 ( fontDescription.slant == item.fontDescription.slant ) )
1472 fontList = item.fallbackFonts;
1474 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1480 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1485 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1486 PointSize26Dot6 requestedPointSize,
1491 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1492 endIt = mFontIdCache.end();
1496 const FontIdCacheItem& item = *it;
1498 if( ( validatedFontId == item.validatedFontId ) &&
1499 ( requestedPointSize == item.requestedPointSize ) )
1501 fontId = item.fontId;
1509 bool FontClient::Plugin::IsScalable( const FontPath& path )
1512 int error = FT_New_Face( mFreeTypeLibrary,
1516 if( FT_Err_Ok != error )
1518 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1520 return ( ftFace->num_fixed_sizes == 0 );
1523 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1525 // Create a font pattern.
1526 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1528 FcResult result = FcResultMatch;
1530 // match the pattern
1531 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1532 bool isScalable = true;
1536 // Get the path to the font file name.
1538 GetFcString( match, FC_FILE, path );
1539 isScalable = IsScalable( path );
1543 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1544 fontDescription.family.c_str(),
1545 fontDescription.width,
1546 fontDescription.weight,
1547 fontDescription.slant );
1549 FcPatternDestroy( fontFamilyPattern );
1550 FcPatternDestroy( match );
1554 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1556 // Empty the caller container
1560 int error = FT_New_Face( mFreeTypeLibrary,
1564 if( FT_Err_Ok != error )
1566 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1569 // Fetch the number of fixed sizes available
1570 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1572 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1574 sizes.PushBack( ftFace->available_sizes[ i ].size );
1579 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1580 Vector< PointSize26Dot6 >& sizes )
1582 // Create a font pattern.
1583 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1585 FcResult result = FcResultMatch;
1587 // match the pattern
1588 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1592 // Get the path to the font file name.
1594 GetFcString( match, FC_FILE, path );
1595 GetFixedSizes( path, sizes );
1599 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1600 fontDescription.family.c_str(),
1601 fontDescription.width,
1602 fontDescription.weight,
1603 fontDescription.slant );
1605 FcPatternDestroy( match );
1606 FcPatternDestroy( fontFamilyPattern );
1609 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
1611 FontDescription description;
1612 description.path = path;
1613 description.family = FontFamily( ftFace->family_name );
1614 description.weight = FontWeight::NONE;
1615 description.width = FontWidth::NONE;
1616 description.slant = FontSlant::NONE;
1618 // Note FreeType doesn't give too much info to build a proper font style.
1619 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1621 description.slant = FontSlant::ITALIC;
1623 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1625 description.weight = FontWeight::BOLD;
1628 FontDescriptionId validatedFontId = 0u;
1629 if( !FindValidatedFont( description,
1632 // Set the index to the vector of paths to font file names.
1633 validatedFontId = mFontDescriptionCache.size();
1635 // Add the path to the cache.
1636 mFontDescriptionCache.push_back( description );
1638 // Cache the index and the font's description.
1639 FontDescriptionCacheItem item( description,
1642 mValidatedFontCache.push_back( item );
1644 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1645 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1651 } // namespace Internal
1653 } // namespace TextAbstraction