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 <adaptor-impl.h>
30 #include <fontconfig/fontconfig.h>
35 #if defined(DEBUG_ENABLED)
36 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
40 * Conversion from Fractional26.6 to float
42 const float FROM_266 = 1.0f / 64.0f;
44 const std::string FONT_FORMAT( "TrueType" );
45 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
46 const int DEFAULT_FONT_WIDTH = 100; // normal
47 const int DEFAULT_FONT_WEIGHT = 80; // normal
48 const int DEFAULT_FONT_SLANT = 0; // normal
50 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
52 const bool FONT_FIXED_SIZE_BITMAP( true );
54 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
65 const int FONT_WIDTH_TYPE_TO_INT[] = { 50, 63, 75, 87, 100, 113, 125, 150, 200 };
66 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
69 // ULTRA_LIGHT, EXTRA_LIGHT 40
71 // DEMI_LIGHT, SEMI_LIGHT 55
75 // DEMI_BOLD, SEMI_BOLD 180
77 // ULTRA_BOLD, EXTRA_BOLD 205
78 // BLACK, HEAVY, EXTRA_BLACK 210
79 const int FONT_WEIGHT_TYPE_TO_INT[] = { 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
80 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
85 const int FONT_SLANT_TYPE_TO_INT[] = { 0, 100, 110 };
86 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
89 * @brief Retrieves a table index for a given value.
91 * @param[in] value The value.
92 * @param[in] table The table.
93 * @param[in] maxIndex The maximum valid index of the table.
95 * @return The index to the closest available value
97 int ValueToIndex( int value, const int* const table, unsigned int maxIndex )
99 if( ( NULL == table ) ||
100 ( value <= table[0] ) )
105 if( value >= table[maxIndex] )
110 for( unsigned int index = 0u; index < maxIndex; )
112 const unsigned int indexPlus = ++index;
113 const int v1 = table[index];
114 const int v2 = table[indexPlus];
115 if( ( v1 < value ) && ( value <= v2 ) )
117 return ( ( value - v1 ) < ( v2 - value ) ) ? index : indexPlus;
133 namespace TextAbstraction
140 * @brief Returns the FontWidth's enum index for the given width value.
142 * @param[in] width The width value.
144 * @return The FontWidth's enum index.
146 FontWidth::Type IntToWidthType( int width )
148 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
152 * @brief Returns the FontWeight's enum index for the given weight value.
154 * @param[in] weight The weight value.
156 * @return The FontWeight's enum index.
158 FontWeight::Type IntToWeightType( int weight )
160 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
164 * @brief Returns the FontSlant's enum index for the given slant value.
166 * @param[in] slant The slant value.
168 * @return The FontSlant's enum index.
170 FontSlant::Type IntToSlantType( int slant )
172 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
175 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list )
176 : fontDescription( font ),
177 fallbackFonts( list )
181 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
182 FontDescriptionId index )
183 : fontDescription( fontDescription ),
188 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
189 PointSize26Dot6 pointSize,
191 : validatedFontId( validatedFontId ),
192 pointSize( pointSize ),
197 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
198 const FontPath& path,
199 PointSize26Dot6 pointSize,
201 const FontMetrics& metrics )
202 : mFreeTypeFace( ftFace ),
204 mPointSize( pointSize ),
207 mFixedWidthPixels( 0.0f ),
208 mFixedHeightPixels( 0.0f ),
209 mIsFixedSizeBitmap( false )
213 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
214 const FontPath& path,
215 PointSize26Dot6 pointSize,
217 const FontMetrics& metrics,
220 : mFreeTypeFace( ftFace ),
222 mPointSize( pointSize ),
225 mFixedWidthPixels( fixedWidth ),
226 mFixedHeightPixels( fixedHeight ),
227 mIsFixedSizeBitmap( true )
231 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
232 unsigned int verticalDpi )
233 : mFreeTypeLibrary( NULL ),
234 mDpiHorizontal( horizontalDpi ),
235 mDpiVertical( verticalDpi ),
239 mValidatedFontCache(),
240 mFontDescriptionCache( 1u ),
244 int error = FT_Init_FreeType( &mFreeTypeLibrary );
245 if( FT_Err_Ok != error )
247 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
251 FontClient::Plugin::~Plugin()
253 for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
257 FallbackCacheItem& item = *it;
259 if( item.fallbackFonts )
261 delete item.fallbackFonts;
262 item.fallbackFonts = NULL;
266 FT_Done_FreeType( mFreeTypeLibrary );
269 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
270 unsigned int verticalDpi )
272 mDpiHorizontal = horizontalDpi;
273 mDpiVertical = verticalDpi;
276 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList )
278 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() );
282 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
284 FcResult result = FcResultMatch;
286 // Match the pattern.
287 FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
289 false /* don't trim */,
293 if( NULL != fontSet )
295 // Reserve some space to avoid reallocations.
296 fontList.reserve( fontSet->nfont );
298 for( int i = 0u; i < fontSet->nfont; ++i )
300 FcPattern* fontPattern = fontSet->fonts[i];
304 // Skip fonts with no path
305 if( GetFcString( fontPattern, FC_FILE, path ) )
307 fontList.push_back( FontDescription() );
308 FontDescription& newFontDescription = fontList.back();
310 newFontDescription.path = path;
315 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
316 GetFcInt( fontPattern, FC_WIDTH, width );
317 GetFcInt( fontPattern, FC_WEIGHT, weight );
318 GetFcInt( fontPattern, FC_SLANT, slant );
319 newFontDescription.width = IntToWidthType( width );
320 newFontDescription.weight = IntToWeightType( weight );
321 newFontDescription.slant = IntToSlantType( slant );
325 FcFontSetDestroy( fontSet );
328 FcPatternDestroy( fontFamilyPattern );
331 void FontClient::Plugin::SetDefaultFont( const FontDescription& fontDescription )
333 SetFontList( fontDescription, mDefaultFonts );
336 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
338 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
340 if( mDefaultFonts.empty() )
342 FontDescription fontDescription;
343 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
344 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
345 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
346 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
347 SetFontList( fontDescription, mDefaultFonts );
350 defaultFonts = mDefaultFonts;
353 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
355 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
357 if ( Adaptor::IsAvailable() )
359 std::string weight; // todo convert weight into enum
360 Dali::Internal::Adaptor::Adaptor& adaptorImpl( Dali::Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ) );
361 adaptorImpl.GetPlatformAbstraction().GetDefaultFontDescription( fontDescription.family, weight );
362 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription Retreived fontFamily:%s\n", fontDescription.family.c_str() );
366 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
368 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
370 if( mSystemFonts.empty() )
375 systemFonts = mSystemFonts;
378 void FontClient::Plugin::GetDescription( FontId id,
379 FontDescription& fontDescription ) const
381 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
382 endIt = mFontIdCache.end();
386 const FontIdCacheItem& item = *it;
388 if( item.fontId == id )
390 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
395 DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
398 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
400 const FontId index = id - 1u;
403 index < mFontCache.size() )
405 return ( *( mFontCache.begin() + index ) ).mPointSize;
409 DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
412 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
415 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
417 PointSize26Dot6 requestedSize,
421 bool foundColor(false);
423 // Traverse the list of fonts.
424 // Check for each default font if supports the character.
426 for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end();
430 const FontDescription& description = *it;
432 FcPattern* pattern = CreateFontFamilyPattern( description );
434 FcResult result = FcResultMatch;
435 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
437 FcCharSet* charSet = NULL;
438 FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
440 if( FcCharSetHasChar( charSet, charcode ) )
442 Vector< PointSize26Dot6 > fixedSizes;
443 GetFixedSizes( description,
446 const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
449 // If the font is not scalable, pick the largest size <= requestedSize
450 PointSize26Dot6 size = fixedSizes[0];
451 for( unsigned int i=1; i<count; ++i )
453 if( fixedSizes[i] <= requestedSize &&
454 fixedSizes[i] > size )
456 size = fixedSizes[i];
459 requestedSize = size;
462 fontId = GetFontId( description,
468 BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
470 Pixel::BGRA8888 == bitmap.GetPixelFormat() )
476 // Keep going unless we prefer a different (color) font
477 if( !preferColor || foundColor )
479 FcPatternDestroy( match );
480 FcPatternDestroy( pattern );
485 FcPatternDestroy( match );
486 FcPatternDestroy( pattern );
492 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
493 PointSize26Dot6 requestedSize,
496 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
500 // Create the list of default fonts if it has not been created.
501 if( mDefaultFonts.empty() )
503 FontDescription fontDescription;
504 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
505 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
506 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
507 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
508 SetFontList( fontDescription, mDefaultFonts );
511 // Traverse the list of default fonts.
512 // Check for each default font if supports the character.
513 fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedSize, preferColor );
518 FontId FontClient::Plugin::FindFallbackFont( FontId preferredFont,
520 PointSize26Dot6 requestedSize,
523 // The font id to be returned.
526 FontDescription fontDescription;
527 GetDescription( preferredFont, fontDescription );
529 // Check first if the font's description has been queried before.
530 FontList* fontList( NULL );
532 if( !FindFallbackFontList( fontDescription, fontList ) )
534 fontList = new FontList;
535 SetFontList( fontDescription, *fontList );
537 // Add the font-list to the cache.
538 mFallbackCache.push_back( FallbackCacheItem(fontDescription, fontList) );
543 fontId = FindFontForCharacter( *fontList, charcode, requestedSize, preferColor );
549 FontId FontClient::Plugin::GetFontId( const FontPath& path,
550 PointSize26Dot6 pointSize,
552 bool cacheDescription )
554 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
558 if( NULL != mFreeTypeLibrary )
561 if( FindFont( path, pointSize, faceIndex, foundId ) )
567 id = CreateFont( path, pointSize, faceIndex, cacheDescription );
574 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
575 PointSize26Dot6 pointSize,
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, pointSize' in the cache.
612 if( !FindFont( validatedFontId, pointSize, 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,
623 // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
624 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
632 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
633 FontDescriptionId& validatedFontId )
635 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
637 // Create a font pattern.
638 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
640 FcResult result = FcResultMatch;
643 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
647 // Get the path to the font file name.
651 FontDescription description;
652 GetFcString( match, FC_FILE, description.path );
653 GetFcString( match, FC_FAMILY, description.family );
654 GetFcInt( match, FC_WIDTH, width );
655 GetFcInt( match, FC_WEIGHT, weight );
656 GetFcInt( match, FC_SLANT, slant );
657 description.width = IntToWidthType( width );
658 description.weight = IntToWeightType( weight );
659 description.slant = IntToSlantType( slant );
661 // Set the index to the vector of paths to font file names.
662 validatedFontId = mFontDescriptionCache.size();
664 // Add the path to the cache.
665 mFontDescriptionCache.push_back( description );
667 // Cache the index and the font's description.
668 FontDescriptionCacheItem item( description,
671 mValidatedFontCache.push_back( item );
673 // destroyed the matched pattern
674 FcPatternDestroy( match );
678 DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
679 fontDescription.family.c_str(),
680 fontDescription.width,
681 fontDescription.weight,
682 fontDescription.slant );
685 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() );
687 // destroy the pattern
688 FcPatternDestroy( fontFamilyPattern );
691 void FontClient::Plugin::GetFontMetrics( FontId fontId,
692 FontMetrics& metrics,
696 fontId-1 < mFontCache.size() )
698 const CacheItem& font = mFontCache[fontId-1];
700 metrics = font.mMetrics;
702 // Adjust the metrics if the fixed-size font should be down-scaled
703 if( font.mIsFixedSizeBitmap &&
704 ( maxFixedSize > 0 ) &&
705 ( font.mFixedHeightPixels > maxFixedSize ) )
707 float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
709 metrics.ascender *= scaleFactor;
710 metrics.descender *= scaleFactor;
711 metrics.height *= scaleFactor;
712 metrics.underlinePosition *= scaleFactor;
713 metrics.underlineThickness *= scaleFactor;
718 DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
722 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
725 GlyphIndex index( 0 );
728 fontId-1 < mFontCache.size() )
730 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
732 index = FT_Get_Char_Index( ftFace, charcode );
738 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
743 bool success( true );
745 for( unsigned int i=0; i<size; ++i )
747 FontId fontId = array[i].fontId;
750 fontId-1 < mFontCache.size() )
752 const CacheItem& font = mFontCache[fontId-1];
754 FT_Face ftFace = font.mFreeTypeFace;
756 #ifdef FREETYPE_BITMAP_SUPPORT
757 // Check to see if we should be loading a Fixed Size bitmap?
758 if ( font.mIsFixedSizeBitmap )
760 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
761 if ( FT_Err_Ok == error )
763 array[i].width = font.mFixedWidthPixels;
764 array[i].height = font.mFixedHeightPixels;
765 array[i].advance = font.mFixedWidthPixels;
766 array[i].xBearing = 0.0f;
767 array[i].yBearing = font.mFixedHeightPixels;
769 // Adjust the metrics if the fixed-size font should be down-scaled
770 if( ( maxFixedSize > 0 ) &&
771 ( font.mFixedHeightPixels > maxFixedSize ) )
773 float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
775 array[i].width *= scaleFactor;
776 array[i].height *= scaleFactor;
777 array[i].advance *= scaleFactor;
778 array[i].xBearing *= scaleFactor;
779 array[i].yBearing *= scaleFactor;
781 array[i].scaleFactor = scaleFactor;
786 DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
793 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
795 if( FT_Err_Ok == error )
797 array[i].width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
798 array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
801 array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
802 array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
806 array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
807 array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
825 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
826 GlyphIndex glyphIndex )
831 fontId-1 < mFontCache.size() )
833 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
837 #ifdef FREETYPE_BITMAP_SUPPORT
838 // Check to see if this is fixed size bitmap
839 if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
841 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
846 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
848 if( FT_Err_Ok == error )
851 error = FT_Get_Glyph( ftFace->glyph, &glyph );
853 // Convert to bitmap if necessary
854 if ( FT_Err_Ok == error )
856 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
858 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
859 if ( FT_Err_Ok == error )
861 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
862 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
866 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
871 ConvertBitmap( bitmap, ftFace->glyph->bitmap );
874 // Created FT_Glyph object must be released with FT_Done_Glyph
875 FT_Done_Glyph( glyph );
880 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
887 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
889 // First look into the cache if there is an ellipsis glyph for the requested point size.
890 for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
891 endIt = mEllipsisCache.End();
895 const EllipsisItem& item = *it;
897 if( fabsf( item.size - pointSize ) < Math::MACHINE_EPSILON_1000 )
899 // Use the glyph in the cache.
904 // No glyph has been found. Create one.
905 mEllipsisCache.PushBack( EllipsisItem() );
906 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
908 item.size = pointSize;
910 // Find a font for the ellipsis glyph.
911 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
915 // Set the character index to access the glyph inside the font.
916 item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
917 ELLIPSIS_CHARACTER );
919 GetGlyphMetrics( &item.glyph, 1u, true, 0 );
924 void FontClient::Plugin::InitSystemFonts()
926 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
928 FcFontSet* fontSet = GetFcFontSet();
932 // Reserve some space to avoid reallocations.
933 mSystemFonts.reserve( fontSet->nfont );
935 for( int i = 0u; i < fontSet->nfont; ++i )
937 FcPattern* fontPattern = fontSet->fonts[i];
941 // Skip fonts with no path
942 if( GetFcString( fontPattern, FC_FILE, path ) )
944 mSystemFonts.push_back( FontDescription() );
945 FontDescription& fontDescription = mSystemFonts.back();
947 fontDescription.path = path;
952 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
953 GetFcInt( fontPattern, FC_WIDTH, width );
954 GetFcInt( fontPattern, FC_WEIGHT, weight );
955 GetFcInt( fontPattern, FC_SLANT, slant );
956 fontDescription.width = IntToWidthType( width );
957 fontDescription.weight = IntToWeightType( weight );
958 fontDescription.slant = IntToSlantType( slant );
959 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
964 FcFontSetDestroy( fontSet );
968 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
970 // create the cached font family lookup pattern
971 // a pattern holds a set of names, each name refers to a property of the font
972 FcPattern* fontFamilyPattern = FcPatternCreate();
974 // add a property to the pattern for the font family
975 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
977 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, FONT_WIDTH_TYPE_TO_INT[fontDescription.width] );
978 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight] );
979 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, FONT_SLANT_TYPE_TO_INT[fontDescription.slant] );
981 // Add a property of the pattern, to say we want to match TrueType fonts
982 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
984 // modify the config, with the mFontFamilyPatterm
985 FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
987 // provide default values for unspecified properties in the font pattern
988 // e.g. patterns without a specified style or weight are set to Medium
989 FcDefaultSubstitute( fontFamilyPattern );
991 return fontFamilyPattern;
994 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
996 // create a new pattern.
997 // a pattern holds a set of names, each name refers to a property of the font
998 FcPattern* pattern = FcPatternCreate();
1000 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1001 FcObjectSet* objectSet = FcObjectSetCreate();
1003 // build an object set from a list of property names
1004 FcObjectSetAdd( objectSet, FC_FILE );
1005 FcObjectSetAdd( objectSet, FC_FAMILY );
1006 FcObjectSetAdd( objectSet, FC_WIDTH );
1007 FcObjectSetAdd( objectSet, FC_WEIGHT );
1008 FcObjectSetAdd( objectSet, FC_SLANT );
1010 // get a list of fonts
1011 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1012 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1014 // clear up the object set
1017 FcObjectSetDestroy( objectSet );
1019 // clear up the pattern
1022 FcPatternDestroy( pattern );
1028 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1029 const char* const n,
1030 std::string& string )
1032 FcChar8* file = NULL;
1033 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1035 if( FcResultMatch == retVal )
1037 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1038 string.assign( reinterpret_cast<const char*>( file ) );
1046 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1048 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1050 if( FcResultMatch == retVal )
1058 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1059 PointSize26Dot6 pointSize,
1060 FaceIndex faceIndex,
1061 bool cacheDescription )
1065 // Create & cache new font face
1067 int error = FT_New_Face( mFreeTypeLibrary,
1072 if( FT_Err_Ok == error )
1074 // Check to see if the font contains fixed sizes?
1075 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1077 // Ensure this size is available
1078 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1080 if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
1082 // Tell Freetype to use this size
1083 error = FT_Select_Size( ftFace, i );
1084 if ( FT_Err_Ok != error )
1086 DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1090 float fixedWidth = static_cast< float >( ftFace->available_sizes[ i ].width );
1091 float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1093 // Indicate that the font is a fixed sized bitmap
1094 FontMetrics metrics( fixedHeight, // The ascender in pixels.
1096 fixedHeight, // The height in pixels.
1100 mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1101 id = mFontCache.size();
1103 if( cacheDescription )
1105 FontDescription description;
1106 description.path = path;
1107 description.family = FontFamily( ftFace->family_name );
1109 // Note FreeType doesn't give too much info to build a proper font style.
1110 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1112 description.slant = FontSlant::ITALIC;
1114 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1116 description.weight = FontWeight::BOLD;
1119 mFontDescriptionCache.push_back( description );
1126 // Can't find this size
1127 std::stringstream sizes;
1128 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1134 sizes << ftFace->available_sizes[ i ].size;
1136 DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1137 path.c_str(), pointSize, sizes.str().c_str() );
1141 error = FT_Set_Char_Size( ftFace,
1147 if( FT_Err_Ok == error )
1150 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1152 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1153 static_cast< float >( ftMetrics.descender ) * FROM_266,
1154 static_cast< float >( ftMetrics.height ) * FROM_266,
1155 static_cast< float >( ftFace->underline_position ) * FROM_266,
1156 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1158 mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
1159 id = mFontCache.size();
1161 if( cacheDescription )
1163 FontDescription description;
1164 description.path = path;
1165 description.family = FontFamily( ftFace->family_name );
1167 // Note FreeType doesn't give too much info to build a proper font style.
1168 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1170 description.slant = FontSlant::ITALIC;
1172 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1174 description.weight = FontWeight::BOLD;
1177 mFontDescriptionCache.push_back( description );
1182 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
1188 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1194 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
1195 FT_Bitmap srcBitmap )
1197 if( srcBitmap.width*srcBitmap.rows > 0 )
1199 switch( srcBitmap.pixel_mode )
1201 case FT_PIXEL_MODE_GRAY:
1203 if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
1205 destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
1207 PixelBuffer* destBuffer = destBitmap.GetBuffer();
1210 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
1214 DALI_LOG_ERROR( "GetBuffer returns null\n" );
1220 #ifdef FREETYPE_BITMAP_SUPPORT
1221 case FT_PIXEL_MODE_BGRA:
1223 if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1225 destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
1227 PixelBuffer* destBuffer = destBitmap.GetBuffer();
1230 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
1234 DALI_LOG_ERROR( "GetBuffer returns null\n" );
1242 DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1249 bool FontClient::Plugin::FindFont( const FontPath& path,
1250 PointSize26Dot6 pointSize,
1251 FaceIndex faceIndex,
1252 FontId& fontId ) const
1255 for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
1256 endIt = mFontCache.end();
1260 const CacheItem& cacheItem = *it;
1262 if( cacheItem.mPointSize == pointSize &&
1263 cacheItem.mFaceIndex == faceIndex &&
1264 cacheItem.mPath == path )
1274 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1275 FontDescriptionId& validatedFontId )
1277 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1279 validatedFontId = 0u;
1281 for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1282 endIt = mValidatedFontCache.end();
1286 const FontDescriptionCacheItem& item = *it;
1288 if( !fontDescription.family.empty() &&
1289 ( fontDescription.family == item.fontDescription.family ) &&
1290 ( fontDescription.width == item.fontDescription.width ) &&
1291 ( fontDescription.weight == item.fontDescription.weight ) &&
1292 ( fontDescription.slant == item.fontDescription.slant ) )
1294 validatedFontId = item.index;
1296 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1302 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1307 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1308 FontList*& fontList )
1310 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1314 for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1318 const FallbackCacheItem& item = *it;
1320 if( !fontDescription.family.empty() &&
1321 ( fontDescription.family == item.fontDescription.family ) &&
1322 ( fontDescription.width == item.fontDescription.width ) &&
1323 ( fontDescription.weight == item.fontDescription.weight ) &&
1324 ( fontDescription.slant == item.fontDescription.slant ) )
1326 fontList = item.fallbackFonts;
1328 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1334 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1339 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1340 PointSize26Dot6 pointSize,
1345 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1346 endIt = mFontIdCache.end();
1350 const FontIdCacheItem& item = *it;
1352 if( ( validatedFontId == item.validatedFontId ) &&
1353 ( pointSize == item.pointSize ) )
1355 fontId = item.fontId;
1363 bool FontClient::Plugin::IsScalable( const FontPath& path )
1366 int error = FT_New_Face( mFreeTypeLibrary,
1370 if( FT_Err_Ok != error )
1372 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1374 return ( ftFace->num_fixed_sizes == 0 );
1377 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1379 // Create a font pattern.
1380 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1382 FcResult result = FcResultMatch;
1384 // match the pattern
1385 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1386 bool isScalable = true;
1390 // Get the path to the font file name.
1392 GetFcString( match, FC_FILE, path );
1393 isScalable = IsScalable( path );
1397 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1398 fontDescription.family.c_str(),
1399 fontDescription.width,
1400 fontDescription.weight,
1401 fontDescription.slant );
1403 FcPatternDestroy( fontFamilyPattern );
1404 FcPatternDestroy( match );
1408 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1410 // Empty the caller container
1414 int error = FT_New_Face( mFreeTypeLibrary,
1418 if( FT_Err_Ok != error )
1420 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1423 // Fetch the number of fixed sizes available
1424 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1426 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1428 sizes.PushBack( ftFace->available_sizes[ i ].size );
1433 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1434 Vector< PointSize26Dot6 >& sizes )
1436 // Create a font pattern.
1437 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1439 FcResult result = FcResultMatch;
1441 // match the pattern
1442 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1446 // Get the path to the font file name.
1448 GetFcString( match, FC_FILE, path );
1449 GetFixedSizes( path, sizes );
1453 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1454 fontDescription.family.c_str(),
1455 fontDescription.width,
1456 fontDescription.weight,
1457 fontDescription.slant );
1459 FcPatternDestroy( match );
1460 FcPatternDestroy( fontFamilyPattern );
1463 } // namespace Internal
1465 } // namespace TextAbstraction