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>
28 #include <fontconfig/fontconfig.h>
31 * Conversion from Fractional26.6 to float
35 const float FROM_266 = 1.0f / 64.0f;
37 const std::string FONT_FORMAT( "TrueType" );
38 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
39 const int DEFAULT_FONT_WIDTH = 100; // normal
40 const int DEFAULT_FONT_WEIGHT = 80; // normal
41 const int DEFAULT_FONT_SLANT = 0; // normal
43 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
45 const bool FONT_FIXED_SIZE_BITMAP( true );
47 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
58 const int FONT_WIDTH_TYPE_TO_INT[] = { 50, 63, 75, 87, 100, 113, 125, 150, 200 };
59 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
62 // ULTRA_LIGHT, EXTRA_LIGHT 40
64 // DEMI_LIGHT, SEMI_LIGHT 55
68 // DEMI_BOLD, SEMI_BOLD 180
70 // ULTRA_BOLD, EXTRA_BOLD 205
71 // BLACK, HEAVY, EXTRA_BLACK 210
72 const int FONT_WEIGHT_TYPE_TO_INT[] = { 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
73 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
78 const int FONT_SLANT_TYPE_TO_INT[] = { 0, 100, 110 };
79 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
82 * @brief Retrieves a table index for a given value.
84 * @param[in] value The value.
85 * @param[in] table The table.
86 * @param[in] maxIndex The maximum valid index of the table.
88 * @return The index to the closest available value
90 int ValueToIndex( int value, const int* const table, unsigned int maxIndex )
92 if( ( NULL == table ) ||
93 ( value <= table[0] ) )
98 if( value >= table[maxIndex] )
103 for( unsigned int index = 0u; index < maxIndex; )
105 const unsigned int indexPlus = ++index;
106 const int v1 = table[index];
107 const int v2 = table[indexPlus];
108 if( ( v1 < value ) && ( value <= v2 ) )
110 return ( ( value - v1 ) < ( v2 - value ) ) ? index : indexPlus;
126 namespace TextAbstraction
133 * @brief Returns the FontWidth's enum index for the given width value.
135 * @param[in] width The width value.
137 * @return The FontWidth's enum index.
139 FontWidth::Type IntToWidthType( int width )
141 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
145 * @brief Returns the FontWeight's enum index for the given weight value.
147 * @param[in] weight The weight value.
149 * @return The FontWeight's enum index.
151 FontWeight::Type IntToWeightType( int weight )
153 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
157 * @brief Returns the FontSlant's enum index for the given slant value.
159 * @param[in] slant The slant value.
161 * @return The FontSlant's enum index.
163 FontSlant::Type IntToSlantType( int slant )
165 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
168 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
169 FontDescriptionId index )
170 : fontDescription( fontDescription ),
175 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
176 PointSize26Dot6 pointSize,
178 : validatedFontId( validatedFontId ),
179 pointSize( pointSize ),
184 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
185 const FontPath& path,
186 PointSize26Dot6 pointSize,
188 const FontMetrics& metrics )
189 : mFreeTypeFace( ftFace ),
191 mPointSize( pointSize ),
194 mFixedWidthPixels( 0.0f ),
195 mFixedHeightPixels( 0.0f ),
196 mIsFixedSizeBitmap( false )
200 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
201 const FontPath& path,
202 PointSize26Dot6 pointSize,
204 const FontMetrics& metrics,
207 : mFreeTypeFace( ftFace ),
209 mPointSize( pointSize ),
212 mFixedWidthPixels( fixedWidth ),
213 mFixedHeightPixels( fixedHeight ),
214 mIsFixedSizeBitmap( true )
218 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
219 unsigned int verticalDpi )
220 : mFreeTypeLibrary( NULL ),
221 mDpiHorizontal( horizontalDpi ),
222 mDpiVertical( verticalDpi ),
226 mValidatedFontCache(),
227 mFontDescriptionCache( 1u ),
231 int error = FT_Init_FreeType( &mFreeTypeLibrary );
232 if( FT_Err_Ok != error )
234 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
238 FontClient::Plugin::~Plugin()
240 FT_Done_FreeType( mFreeTypeLibrary );
243 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
244 unsigned int verticalDpi )
246 mDpiHorizontal = horizontalDpi;
247 mDpiVertical = verticalDpi;
250 void FontClient::Plugin::SetDefaultFont( const FontDescription& fontDescription )
252 mDefaultFonts.clear();
254 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
256 FcResult result = FcResultMatch;
258 // Match the pattern.
259 FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
261 false /* don't trim */,
265 if( NULL != fontSet )
267 // Reserve some space to avoid reallocations.
268 mDefaultFonts.reserve( fontSet->nfont );
270 for( int i = 0u; i < fontSet->nfont; ++i )
272 FcPattern* fontPattern = fontSet->fonts[i];
276 // Skip fonts with no path
277 if( GetFcString( fontPattern, FC_FILE, path ) )
279 mDefaultFonts.push_back( FontDescription() );
280 FontDescription& newFontDescription = mDefaultFonts.back();
282 newFontDescription.path = path;
287 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
288 GetFcInt( fontPattern, FC_WIDTH, width );
289 GetFcInt( fontPattern, FC_WEIGHT, weight );
290 GetFcInt( fontPattern, FC_SLANT, slant );
291 newFontDescription.width = IntToWidthType( width );
292 newFontDescription.weight = IntToWeightType( weight );
293 newFontDescription.slant = IntToSlantType( slant );
297 FcFontSetDestroy( fontSet );
300 FcPatternDestroy( fontFamilyPattern );
303 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
305 if( mDefaultFonts.empty() )
307 FontDescription fontDescription;
308 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
309 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
310 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
311 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
312 SetDefaultFont( fontDescription );
315 defaultFonts = mDefaultFonts;
318 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
320 if( mSystemFonts.empty() )
325 systemFonts = mSystemFonts;
328 void FontClient::Plugin::GetDescription( FontId id,
329 FontDescription& fontDescription ) const
331 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
332 endIt = mFontIdCache.end();
336 const FontIdCacheItem& item = *it;
338 if( item.fontId == id )
340 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
345 DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
348 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
350 const FontId index = id - 1u;
353 index < mFontCache.size() )
355 return ( *( mFontCache.begin() + index ) ).mPointSize;
359 DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
362 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
365 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
366 PointSize26Dot6 requestedSize,
370 bool foundColor(false);
372 // Create the list of default fonts if it has not been created.
373 if( mDefaultFonts.empty() )
375 FontDescription fontDescription;
376 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
377 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
378 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
379 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
380 SetDefaultFont( fontDescription );
383 // Traverse the list of default fonts.
384 // Check for each default font if supports the character.
386 for( FontList::const_iterator it = mDefaultFonts.begin(), endIt = mDefaultFonts.end();
390 const FontDescription& description = *it;
392 FcPattern* pattern = CreateFontFamilyPattern( description );
394 FcResult result = FcResultMatch;
395 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
397 FcCharSet* charSet = NULL;
398 FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
400 if( FcCharSetHasChar( charSet, charcode ) )
402 Vector< PointSize26Dot6 > fixedSizes;
403 GetFixedSizes( description,
406 const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
409 // If the font is not scalable, pick the largest size <= requestedSize
410 PointSize26Dot6 size = fixedSizes[0];
411 for( unsigned int i=1; i<count; ++i )
413 if( fixedSizes[i] <= requestedSize &&
414 fixedSizes[i] > size )
416 size = fixedSizes[i];
419 requestedSize = size;
422 fontId = GetFontId( description,
428 BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
430 Pixel::BGRA8888 == bitmap.GetPixelFormat() )
436 // Keep going unless we prefer a different (color) font
437 if( !preferColor || foundColor )
439 FcPatternDestroy( match );
440 FcPatternDestroy( pattern );
445 FcPatternDestroy( match );
446 FcPatternDestroy( pattern );
451 FontId FontClient::Plugin::GetFontId( const FontPath& path,
452 PointSize26Dot6 pointSize,
454 bool cacheDescription )
458 if( NULL != mFreeTypeLibrary )
461 if( FindFont( path, pointSize, faceIndex, foundId ) )
467 id = CreateFont( path, pointSize, faceIndex, cacheDescription );
474 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
475 PointSize26Dot6 pointSize,
476 FaceIndex faceIndex )
478 // This method uses three vectors which caches:
479 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
480 // * The path to font file names.
481 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
483 // 1) Checks in the cache if the font's description has been validated before.
484 // If it was it gets an index to the vector with paths to font file names. Otherwise,
485 // retrieves using font config a path to a font file name which matches with the
486 // font's description. The path is stored in the chache.
488 // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
489 // fon file names' exists. If exists, it gets the font id. If it doesn't it calls
490 // the GetFontId() method with the path to the font file name and the point size to
493 // The font id to be returned.
496 // Check first if the font's description have been validated before.
497 FontDescriptionId validatedFontId = 0u;
499 if( !FindValidatedFont( fontDescription,
502 // Use font config to validate the font's description.
503 ValidateFont( fontDescription,
507 // Check if exists a pair 'validatedFontId, pointSize' in the cache.
508 if( !FindFont( validatedFontId, pointSize, fontId ) )
510 // Retrieve the font file name path.
511 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
513 // Retrieve the font id. Do not cache the description as it has been already cached.
514 fontId = GetFontId( description.path,
519 // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
520 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
528 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
529 FontDescriptionId& validatedFontId )
531 // Create a font pattern.
532 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
534 FcResult result = FcResultMatch;
537 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
541 // Get the path to the font file name.
545 FontDescription description;
546 GetFcString( match, FC_FILE, description.path );
547 GetFcString( match, FC_FAMILY, description.family );
548 GetFcInt( match, FC_WIDTH, width );
549 GetFcInt( match, FC_WEIGHT, weight );
550 GetFcInt( match, FC_SLANT, slant );
551 description.width = IntToWidthType( width );
552 description.weight = IntToWeightType( weight );
553 description.slant = IntToSlantType( slant );
555 // Set the index to the vector of paths to font file names.
556 validatedFontId = mFontDescriptionCache.size();
558 // Add the path to the cache.
559 mFontDescriptionCache.push_back( description );
561 // Cache the index and the font's description.
562 FontDescriptionCacheItem item( description,
565 mValidatedFontCache.push_back( item );
567 // destroyed the matched pattern
568 FcPatternDestroy( match );
572 DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
573 fontDescription.family.c_str(),
574 fontDescription.width,
575 fontDescription.weight,
576 fontDescription.slant );
579 // destroy the pattern
580 FcPatternDestroy( fontFamilyPattern );
583 void FontClient::Plugin::GetFontMetrics( FontId fontId,
584 FontMetrics& metrics,
588 fontId-1 < mFontCache.size() )
590 const CacheItem& font = mFontCache[fontId-1];
592 metrics = font.mMetrics;
594 // Adjust the metrics if the fixed-size font should be down-scaled
595 if( font.mIsFixedSizeBitmap &&
596 ( maxFixedSize > 0 ) &&
597 ( font.mFixedHeightPixels > maxFixedSize ) )
599 float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
601 metrics.ascender *= scaleFactor;
602 metrics.descender *= scaleFactor;
603 metrics.height *= scaleFactor;
604 metrics.underlinePosition *= scaleFactor;
605 metrics.underlineThickness *= scaleFactor;
610 DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
614 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
617 GlyphIndex index( 0 );
620 fontId-1 < mFontCache.size() )
622 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
624 index = FT_Get_Char_Index( ftFace, charcode );
630 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
635 bool success( true );
637 for( unsigned int i=0; i<size; ++i )
639 FontId fontId = array[i].fontId;
642 fontId-1 < mFontCache.size() )
644 const CacheItem& font = mFontCache[fontId-1];
646 FT_Face ftFace = font.mFreeTypeFace;
648 #ifdef FREETYPE_BITMAP_SUPPORT
649 // Check to see if we should be loading a Fixed Size bitmap?
650 if ( font.mIsFixedSizeBitmap )
652 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
653 if ( FT_Err_Ok == error )
655 array[i].width = font.mFixedWidthPixels;
656 array[i].height = font.mFixedHeightPixels;
657 array[i].advance = font.mFixedWidthPixels;
658 array[i].xBearing = 0.0f;
659 array[i].yBearing = font.mFixedHeightPixels;
661 // Adjust the metrics if the fixed-size font should be down-scaled
662 if( ( maxFixedSize > 0 ) &&
663 ( font.mFixedHeightPixels > maxFixedSize ) )
665 float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
667 array[i].width *= scaleFactor;
668 array[i].height *= scaleFactor;
669 array[i].advance *= scaleFactor;
670 array[i].xBearing *= scaleFactor;
671 array[i].yBearing *= scaleFactor;
673 array[i].scaleFactor = scaleFactor;
678 DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
685 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
687 if( FT_Err_Ok == error )
689 array[i].width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
690 array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
693 array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
694 array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
698 array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
699 array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
717 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
718 GlyphIndex glyphIndex )
723 fontId-1 < mFontCache.size() )
725 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
729 #ifdef FREETYPE_BITMAP_SUPPORT
730 // Check to see if this is fixed size bitmap
731 if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
733 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
738 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
740 if( FT_Err_Ok == error )
743 error = FT_Get_Glyph( ftFace->glyph, &glyph );
745 // Convert to bitmap if necessary
746 if ( FT_Err_Ok == error )
748 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
750 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
751 if ( FT_Err_Ok == error )
753 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
754 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
758 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
763 ConvertBitmap( bitmap, ftFace->glyph->bitmap );
766 // Created FT_Glyph object must be released with FT_Done_Glyph
767 FT_Done_Glyph( glyph );
772 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
779 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
781 // First look into the cache if there is an ellipsis glyph for the requested point size.
782 for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
783 endIt = mEllipsisCache.End();
787 const EllipsisItem& item = *it;
789 if( fabsf( item.size - pointSize ) < Math::MACHINE_EPSILON_1000 )
791 // Use the glyph in the cache.
796 // No glyph has been found. Create one.
797 mEllipsisCache.PushBack( EllipsisItem() );
798 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
800 item.size = pointSize;
802 // Find a font for the ellipsis glyph.
803 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
807 // Set the character index to access the glyph inside the font.
808 item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
809 ELLIPSIS_CHARACTER );
811 GetGlyphMetrics( &item.glyph, 1u, true, 0 );
816 void FontClient::Plugin::InitSystemFonts()
818 FcFontSet* fontSet = GetFcFontSet();
822 // Reserve some space to avoid reallocations.
823 mSystemFonts.reserve( fontSet->nfont );
825 for( int i = 0u; i < fontSet->nfont; ++i )
827 FcPattern* fontPattern = fontSet->fonts[i];
831 // Skip fonts with no path
832 if( GetFcString( fontPattern, FC_FILE, path ) )
834 mSystemFonts.push_back( FontDescription() );
835 FontDescription& fontDescription = mSystemFonts.back();
837 fontDescription.path = path;
842 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
843 GetFcInt( fontPattern, FC_WIDTH, width );
844 GetFcInt( fontPattern, FC_WEIGHT, weight );
845 GetFcInt( fontPattern, FC_SLANT, slant );
846 fontDescription.width = IntToWidthType( width );
847 fontDescription.weight = IntToWeightType( weight );
848 fontDescription.slant = IntToSlantType( slant );
852 FcFontSetDestroy( fontSet );
856 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
858 // create the cached font family lookup pattern
859 // a pattern holds a set of names, each name refers to a property of the font
860 FcPattern* fontFamilyPattern = FcPatternCreate();
862 // add a property to the pattern for the font family
863 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
865 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, FONT_WIDTH_TYPE_TO_INT[fontDescription.width] );
866 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight] );
867 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, FONT_SLANT_TYPE_TO_INT[fontDescription.slant] );
869 // Add a property of the pattern, to say we want to match TrueType fonts
870 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
872 // modify the config, with the mFontFamilyPatterm
873 FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
875 // provide default values for unspecified properties in the font pattern
876 // e.g. patterns without a specified style or weight are set to Medium
877 FcDefaultSubstitute( fontFamilyPattern );
879 return fontFamilyPattern;
882 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
884 // create a new pattern.
885 // a pattern holds a set of names, each name refers to a property of the font
886 FcPattern* pattern = FcPatternCreate();
888 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
889 FcObjectSet* objectSet = FcObjectSetCreate();
891 // build an object set from a list of property names
892 FcObjectSetAdd( objectSet, FC_FILE );
893 FcObjectSetAdd( objectSet, FC_FAMILY );
894 FcObjectSetAdd( objectSet, FC_WIDTH );
895 FcObjectSetAdd( objectSet, FC_WEIGHT );
896 FcObjectSetAdd( objectSet, FC_SLANT );
898 // get a list of fonts
899 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
900 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
902 // clear up the object set
905 FcObjectSetDestroy( objectSet );
907 // clear up the pattern
910 FcPatternDestroy( pattern );
916 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
918 std::string& string )
920 FcChar8* file = NULL;
921 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
923 if( FcResultMatch == retVal )
925 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
926 string.assign( reinterpret_cast<const char*>( file ) );
934 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
936 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
938 if( FcResultMatch == retVal )
946 FontId FontClient::Plugin::CreateFont( const FontPath& path,
947 PointSize26Dot6 pointSize,
949 bool cacheDescription )
953 // Create & cache new font face
955 int error = FT_New_Face( mFreeTypeLibrary,
960 if( FT_Err_Ok == error )
962 // Check to see if the font contains fixed sizes?
963 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
965 // Ensure this size is available
966 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
968 if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
970 // Tell Freetype to use this size
971 error = FT_Select_Size( ftFace, i );
972 if ( FT_Err_Ok != error )
974 DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
978 float fixedWidth = static_cast< float >( ftFace->available_sizes[ i ].width );
979 float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
981 // Indicate that the font is a fixed sized bitmap
982 FontMetrics metrics( fixedHeight, // The ascender in pixels.
984 fixedHeight, // The height in pixels.
988 mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
989 id = mFontCache.size();
991 if( cacheDescription )
993 FontDescription description;
994 description.path = path;
995 description.family = FontFamily( ftFace->family_name );
997 // Note FreeType doesn't give too much info to build a proper font style.
998 if( ftFace->style_flags | FT_STYLE_FLAG_ITALIC )
1000 description.slant = FontSlant::ITALIC;
1002 if( ftFace->style_flags | FT_STYLE_FLAG_BOLD )
1004 description.weight = FontWeight::BOLD;
1007 mFontDescriptionCache.push_back( description );
1014 // Can't find this size
1015 std::stringstream sizes;
1016 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1022 sizes << ftFace->available_sizes[ i ].size;
1024 DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1025 path.c_str(), pointSize, sizes.str().c_str() );
1029 error = FT_Set_Char_Size( ftFace,
1035 if( FT_Err_Ok == error )
1038 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1040 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1041 static_cast< float >( ftMetrics.descender ) * FROM_266,
1042 static_cast< float >( ftMetrics.height ) * FROM_266,
1043 static_cast< float >( ftFace->underline_position ) * FROM_266,
1044 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1046 mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
1047 id = mFontCache.size();
1049 if( cacheDescription )
1051 FontDescription description;
1052 description.path = path;
1053 description.family = FontFamily( ftFace->family_name );
1055 // Note FreeType doesn't give too much info to build a proper font style.
1056 if( ftFace->style_flags | FT_STYLE_FLAG_ITALIC )
1058 description.slant = FontSlant::ITALIC;
1060 if( ftFace->style_flags | FT_STYLE_FLAG_BOLD )
1062 description.weight = FontWeight::BOLD;
1065 mFontDescriptionCache.push_back( description );
1070 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
1076 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1082 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
1083 FT_Bitmap srcBitmap )
1085 if( srcBitmap.width*srcBitmap.rows > 0 )
1087 switch( srcBitmap.pixel_mode )
1089 case FT_PIXEL_MODE_GRAY:
1091 if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
1093 destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
1095 PixelBuffer* destBuffer = destBitmap.GetBuffer();
1098 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
1102 DALI_LOG_ERROR( "GetBuffer returns null\n" );
1108 #ifdef FREETYPE_BITMAP_SUPPORT
1109 case FT_PIXEL_MODE_BGRA:
1111 if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1113 destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
1115 PixelBuffer* destBuffer = destBitmap.GetBuffer();
1118 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
1122 DALI_LOG_ERROR( "GetBuffer returns null\n" );
1130 DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1137 bool FontClient::Plugin::FindFont( const FontPath& path,
1138 PointSize26Dot6 pointSize,
1139 FaceIndex faceIndex,
1140 FontId& fontId ) const
1143 for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
1144 endIt = mFontCache.end();
1148 const CacheItem& cacheItem = *it;
1150 if( cacheItem.mPointSize == pointSize &&
1151 cacheItem.mFaceIndex == faceIndex &&
1152 cacheItem.mPath == path )
1162 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1163 FontDescriptionId& validatedFontId )
1165 validatedFontId = 0u;
1167 for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1168 endIt = mValidatedFontCache.end();
1172 const FontDescriptionCacheItem& item = *it;
1174 if( !fontDescription.family.empty() &&
1175 ( fontDescription.family == item.fontDescription.family ) &&
1176 ( fontDescription.width == item.fontDescription.width ) &&
1177 ( fontDescription.weight == item.fontDescription.weight ) &&
1178 ( fontDescription.slant == item.fontDescription.slant ) )
1180 validatedFontId = item.index;
1189 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1190 PointSize26Dot6 pointSize,
1195 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1196 endIt = mFontIdCache.end();
1200 const FontIdCacheItem& item = *it;
1202 if( ( validatedFontId == item.validatedFontId ) &&
1203 ( pointSize == item.pointSize ) )
1205 fontId = item.fontId;
1213 bool FontClient::Plugin::IsScalable( const FontPath& path )
1216 int error = FT_New_Face( mFreeTypeLibrary,
1220 if( FT_Err_Ok != error )
1222 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1224 return ( ftFace->num_fixed_sizes == 0 );
1227 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1229 // Create a font pattern.
1230 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1232 FcResult result = FcResultMatch;
1234 // match the pattern
1235 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1236 bool isScalable = true;
1240 // Get the path to the font file name.
1242 GetFcString( match, FC_FILE, path );
1243 isScalable = IsScalable( path );
1247 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1248 fontDescription.family.c_str(),
1249 fontDescription.width,
1250 fontDescription.weight,
1251 fontDescription.slant );
1253 FcPatternDestroy( fontFamilyPattern );
1254 FcPatternDestroy( match );
1258 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1260 // Empty the caller container
1264 int error = FT_New_Face( mFreeTypeLibrary,
1268 if( FT_Err_Ok != error )
1270 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1273 // Fetch the number of fixed sizes available
1274 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1276 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1278 sizes.PushBack( ftFace->available_sizes[ i ].size );
1283 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1284 Vector< PointSize26Dot6 >& sizes )
1286 // Create a font pattern.
1287 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1289 FcResult result = FcResultMatch;
1291 // match the pattern
1292 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1296 // Get the path to the font file name.
1298 GetFcString( match, FC_FILE, path );
1299 GetFixedSizes( path, sizes );
1303 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1304 fontDescription.family.c_str(),
1305 fontDescription.width,
1306 fontDescription.weight,
1307 fontDescription.slant );
1309 FcPatternDestroy( match );
1310 FcPatternDestroy( fontFamilyPattern );
1313 } // namespace Internal
1315 } // namespace TextAbstraction