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 <adaptor-impl.h>
31 #include <fontconfig/fontconfig.h>
36 #if defined(DEBUG_ENABLED)
37 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
41 * Conversion from Fractional26.6 to float
43 const float FROM_266 = 1.0f / 64.0f;
44 const float POINTS_PER_INCH = 72.f;
46 const std::string FONT_FORMAT( "TrueType" );
47 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
48 const int DEFAULT_FONT_WIDTH = 100; // normal
49 const int DEFAULT_FONT_WEIGHT = 80; // normal
50 const int DEFAULT_FONT_SLANT = 0; // normal
52 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
54 const bool FONT_FIXED_SIZE_BITMAP( true );
56 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
58 // NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
68 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
69 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
71 // NONE -1 --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
73 // ULTRA_LIGHT, EXTRA_LIGHT 40
75 // DEMI_LIGHT, SEMI_LIGHT 55
79 // DEMI_BOLD, SEMI_BOLD 180
81 // ULTRA_BOLD, EXTRA_BOLD 205
82 // BLACK, HEAVY, EXTRA_BLACK 210
83 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
84 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
86 // NONE -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
90 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
91 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
100 namespace TextAbstraction
107 * @brief Returns the FontWidth's enum index for the given width value.
109 * @param[in] width The width value.
111 * @return The FontWidth's enum index.
113 FontWidth::Type IntToWidthType( int width )
115 return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
119 * @brief Returns the FontWeight's enum index for the given weight value.
121 * @param[in] weight The weight value.
123 * @return The FontWeight's enum index.
125 FontWeight::Type IntToWeightType( int weight )
127 return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
131 * @brief Returns the FontSlant's enum index for the given slant value.
133 * @param[in] slant The slant value.
135 * @return The FontSlant's enum index.
137 FontSlant::Type IntToSlantType( int slant )
139 return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
142 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list )
143 : fontDescription( font ),
144 fallbackFonts( list )
148 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
149 FontDescriptionId index )
150 : fontDescription( fontDescription ),
155 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
156 PointSize26Dot6 requestedPointSize,
158 : validatedFontId( validatedFontId ),
159 requestedPointSize( requestedPointSize ),
164 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
165 const FontPath& path,
166 PointSize26Dot6 requestedPointSize,
168 const FontMetrics& metrics )
169 : mFreeTypeFace( ftFace ),
171 mRequestedPointSize( requestedPointSize ),
174 mFixedWidthPixels( 0.0f ),
175 mFixedHeightPixels( 0.0f ),
177 mIsFixedSizeBitmap( false )
181 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
182 const FontPath& path,
183 PointSize26Dot6 requestedPointSize,
185 const FontMetrics& metrics,
188 : mFreeTypeFace( ftFace ),
190 mRequestedPointSize( requestedPointSize ),
193 mFixedWidthPixels( fixedWidth ),
194 mFixedHeightPixels( fixedHeight ),
196 mIsFixedSizeBitmap( true )
200 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
201 unsigned int verticalDpi )
202 : mFreeTypeLibrary( NULL ),
203 mDpiHorizontal( horizontalDpi ),
204 mDpiVertical( verticalDpi ),
205 mDefaultFontDescription(),
209 mValidatedFontCache(),
210 mFontDescriptionCache( 1u ),
212 mVectorFontCache( NULL ),
214 mDefaultFontDescriptionCached( false )
216 int error = FT_Init_FreeType( &mFreeTypeLibrary );
217 if( FT_Err_Ok != error )
219 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
222 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
223 mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
227 FontClient::Plugin::~Plugin()
229 for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
233 FallbackCacheItem& item = *it;
235 if( item.fallbackFonts )
237 delete item.fallbackFonts;
238 item.fallbackFonts = NULL;
242 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
243 delete mVectorFontCache;
246 FT_Done_FreeType( mFreeTypeLibrary );
249 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
250 unsigned int verticalDpi )
252 mDpiHorizontal = horizontalDpi;
253 mDpiVertical = verticalDpi;
256 void FontClient::Plugin::ResetSystemDefaults()
258 mDefaultFontDescriptionCached = false;
261 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList )
263 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() );
267 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
269 FcResult result = FcResultMatch;
271 // Match the pattern.
272 FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
274 false /* don't trim */,
278 if( NULL != fontSet )
280 // Reserve some space to avoid reallocations.
281 fontList.reserve( fontSet->nfont );
283 for( int i = 0u; i < fontSet->nfont; ++i )
285 FcPattern* fontPattern = fontSet->fonts[i];
289 // Skip fonts with no path
290 if( GetFcString( fontPattern, FC_FILE, path ) )
292 fontList.push_back( FontDescription() );
293 FontDescription& newFontDescription = fontList.back();
295 newFontDescription.path = path;
300 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
301 GetFcInt( fontPattern, FC_WIDTH, width );
302 GetFcInt( fontPattern, FC_WEIGHT, weight );
303 GetFcInt( fontPattern, FC_SLANT, slant );
304 newFontDescription.width = IntToWidthType( width );
305 newFontDescription.weight = IntToWeightType( weight );
306 newFontDescription.slant = IntToSlantType( slant );
310 FcFontSetDestroy( fontSet );
313 FcPatternDestroy( fontFamilyPattern );
316 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
318 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
320 if( mDefaultFonts.empty() )
322 FontDescription fontDescription;
323 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
324 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
325 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
326 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
327 SetFontList( fontDescription, mDefaultFonts );
330 defaultFonts = mDefaultFonts;
333 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
335 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
337 if( !mDefaultFontDescriptionCached )
339 FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
341 FcPattern* matchPattern = FcPatternCreate();
342 FcConfigSubstitute(NULL, matchPattern, FcMatchPattern);
343 FcDefaultSubstitute( matchPattern );
345 MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription );
346 FcPatternDestroy( matchPattern );
348 mDefaultFontDescriptionCached = true;
351 fontDescription.path = mDefaultFontDescription.path;
352 fontDescription.family = mDefaultFontDescription.family;
353 fontDescription.width = mDefaultFontDescription.width;
354 fontDescription.weight = mDefaultFontDescription.weight;
355 fontDescription.slant = mDefaultFontDescription.slant;
358 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
360 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
362 if( mSystemFonts.empty() )
367 systemFonts = mSystemFonts;
370 void FontClient::Plugin::GetDescription( FontId id,
371 FontDescription& fontDescription ) const
373 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
374 endIt = mFontIdCache.end();
378 const FontIdCacheItem& item = *it;
380 if( item.fontId == id )
382 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
387 DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
390 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
392 const FontId index = id - 1u;
395 index < mFontCache.size() )
397 return ( *( mFontCache.begin() + index ) ).mRequestedPointSize;
401 DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
404 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
407 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
409 PointSize26Dot6 requestedPointSize,
412 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFontForCharacter\n");
415 bool foundColor = false;
417 // Traverse the list of fonts.
418 // Check for each font if supports the character.
419 for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end();
423 const FontDescription& description = *it;
425 FcPattern* pattern = CreateFontFamilyPattern( description );
427 FcResult result = FcResultMatch;
428 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
430 FcCharSet* charSet = NULL;
431 FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
433 if( FcCharSetHasChar( charSet, charcode ) )
435 Vector< PointSize26Dot6 > fixedSizes;
436 GetFixedSizes( description,
439 PointSize26Dot6 actualPointSize = requestedPointSize;
441 const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
445 // If the font is not scalable, pick the largest size <= requestedPointSize
446 actualPointSize = fixedSizes[0];
447 for( unsigned int i=1; i<count; ++i )
449 if( fixedSizes[i] <= requestedPointSize &&
450 fixedSizes[i] > actualPointSize )
452 actualPointSize = fixedSizes[i];
457 fontId = GetFontId( description,
464 PixelData bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
466 Pixel::BGRA8888 == bitmap.GetPixelFormat() )
472 // Keep going unless we prefer a different (color) font.
473 if( !preferColor || foundColor )
475 FcPatternDestroy( match );
476 FcPatternDestroy( pattern );
481 FcPatternDestroy( match );
482 FcPatternDestroy( pattern );
488 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
489 PointSize26Dot6 requestedPointSize,
492 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
496 // Create the list of default fonts if it has not been created.
497 if( mDefaultFonts.empty() )
499 FontDescription fontDescription;
500 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
501 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
502 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
503 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
505 SetFontList( fontDescription, mDefaultFonts );
508 // Traverse the list of default fonts.
509 // Check for each default font if supports the character.
510 fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedPointSize, preferColor );
515 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
516 const FontDescription& preferredFontDescription,
517 PointSize26Dot6 requestedPointSize,
520 // The font id to be returned.
523 FontDescription fontDescription;
525 // Fill the font description with the preferred font description and complete with the defaults.
526 fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
527 fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
528 fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
529 fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
531 // Check first if the font's description has been queried before.
532 FontList* fontList( NULL );
534 if( !FindFallbackFontList( fontDescription, fontList ) )
536 fontList = new FontList;
537 SetFontList( fontDescription, *fontList );
539 // Add the font-list to the cache.
540 mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList ) );
545 fontId = FindFontForCharacter( *fontList, charcode, requestedPointSize, preferColor );
551 FontId FontClient::Plugin::GetFontId( const FontPath& path,
552 PointSize26Dot6 requestedPointSize,
553 PointSize26Dot6 actualPointSize,
555 bool cacheDescription )
557 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
561 if( NULL != mFreeTypeLibrary )
564 if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
570 id = CreateFont( path, requestedPointSize, actualPointSize, faceIndex, cacheDescription );
577 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
578 PointSize26Dot6 requestedPointSize,
579 PointSize26Dot6 actualPointSize,
580 FaceIndex faceIndex )
582 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() );
584 // This method uses three vectors which caches:
585 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
586 // * The path to font file names.
587 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
589 // 1) Checks in the cache if the font's description has been validated before.
590 // If it was it gets an index to the vector with paths to font file names. Otherwise,
591 // retrieves using font config a path to a font file name which matches with the
592 // font's description. The path is stored in the cache.
594 // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
595 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
596 // the GetFontId() method with the path to the font file name and the point size to
599 // The font id to be returned.
602 // Check first if the font's description have been validated before.
603 FontDescriptionId validatedFontId = 0u;
605 if( !FindValidatedFont( fontDescription,
608 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n");
610 // Use font config to validate the font's description.
611 ValidateFont( fontDescription,
615 // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
616 if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
618 // Retrieve the font file name path.
619 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
621 // Retrieve the font id. Do not cache the description as it has been already cached.
622 fontId = GetFontId( description.path,
628 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
629 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
637 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
638 FontDescriptionId& validatedFontId )
640 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
642 // Create a font pattern.
643 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
645 FontDescription description;
647 bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description );
648 FcPatternDestroy( fontFamilyPattern );
652 // Set the index to the vector of paths to font file names.
653 validatedFontId = mFontDescriptionCache.size();
655 // Add the path to the cache.
656 mFontDescriptionCache.push_back( description );
658 // Cache the index and the matched font's description.
659 FontDescriptionCacheItem item( description,
662 mValidatedFontCache.push_back( item );
664 if( ( fontDescription.family != description.family ) ||
665 ( fontDescription.width != description.width ) ||
666 ( fontDescription.weight != description.weight ) ||
667 ( fontDescription.slant != description.slant ) )
669 // Cache the given font's description if it's different than the matched.
670 FontDescriptionCacheItem item( fontDescription,
673 mValidatedFontCache.push_back( item );
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() );
688 void FontClient::Plugin::GetFontMetrics( FontId fontId,
689 FontMetrics& metrics )
691 if( ( fontId > 0 ) &&
692 ( fontId - 1u < mFontCache.size() ) )
694 const FontFaceCacheItem& font = mFontCache[fontId-1];
696 metrics = font.mMetrics;
698 // Adjust the metrics if the fixed-size font should be down-scaled
699 if( font.mIsFixedSizeBitmap )
701 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
703 if( desiredFixedSize > 0.f )
705 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
707 metrics.ascender = floorf( metrics.ascender * scaleFactor );
708 metrics.descender = floorf( metrics.descender * scaleFactor );
709 metrics.height = floorf( metrics.height * scaleFactor );
710 metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
711 metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
717 DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
721 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
724 GlyphIndex index( 0 );
727 fontId-1 < mFontCache.size() )
729 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
731 index = FT_Get_Char_Index( ftFace, charcode );
737 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
742 if( VECTOR_GLYPH == type )
744 return GetVectorMetrics( array, size, horizontal );
747 return GetBitmapMetrics( array, size, horizontal );
750 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
754 bool success( true );
756 for( unsigned int i=0; i<size; ++i )
758 GlyphInfo& glyph = array[i];
760 FontId fontId = glyph.fontId;
763 fontId-1 < mFontCache.size() )
765 const FontFaceCacheItem& font = mFontCache[fontId-1];
767 FT_Face ftFace = font.mFreeTypeFace;
769 #ifdef FREETYPE_BITMAP_SUPPORT
770 // Check to see if we should be loading a Fixed Size bitmap?
771 if ( font.mIsFixedSizeBitmap )
773 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
774 if ( FT_Err_Ok == error )
776 glyph.width = font.mFixedWidthPixels;
777 glyph.height = font.mFixedHeightPixels;
778 glyph.advance = font.mFixedWidthPixels;
779 glyph.xBearing = 0.0f;
780 glyph.yBearing = font.mFixedHeightPixels;
782 // Adjust the metrics if the fixed-size font should be down-scaled
783 const float desiredFixedSize = static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
785 if( desiredFixedSize > 0.f )
787 const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
789 glyph.width = floorf( glyph.width * scaleFactor );
790 glyph.height = floorf( glyph.height * scaleFactor );
791 glyph.advance = floorf( glyph.advance * scaleFactor );
792 glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
793 glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
795 glyph.scaleFactor = scaleFactor;
800 DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
807 int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_DEFAULT );
809 if( FT_Err_Ok == error )
811 glyph.width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
812 glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
815 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
816 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
820 glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
821 glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
839 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
843 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
844 bool success( true );
846 for( unsigned int i=0; i<size; ++i )
848 FontId fontId = array[i].fontId;
851 fontId-1 < mFontCache.size() )
853 FontFaceCacheItem& font = mFontCache[fontId-1];
855 if( ! font.mVectorFontId )
857 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
860 mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
862 // Vector metrics are in EMs, convert to pixels
863 const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
864 array[i].width *= scale;
865 array[i].height *= scale;
866 array[i].xBearing *= scale;
867 array[i].yBearing *= scale;
868 array[i].advance *= scale;
882 PixelData FontClient::Plugin::CreateBitmap( FontId fontId,
883 GlyphIndex glyphIndex )
888 fontId-1 < mFontCache.size() )
890 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
894 #ifdef FREETYPE_BITMAP_SUPPORT
895 // Check to see if this is fixed size bitmap
896 if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
898 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
903 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
905 if( FT_Err_Ok == error )
908 error = FT_Get_Glyph( ftFace->glyph, &glyph );
910 // Convert to bitmap if necessary
911 if ( FT_Err_Ok == error )
913 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
915 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
916 if ( FT_Err_Ok == error )
918 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
919 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
923 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
928 ConvertBitmap( bitmap, ftFace->glyph->bitmap );
931 // Created FT_Glyph object must be released with FT_Done_Glyph
932 FT_Done_Glyph( glyph );
937 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
944 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
949 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
951 fontId-1 < mFontCache.size() )
953 FontFaceCacheItem& font = mFontCache[fontId-1];
955 if( ! font.mVectorFontId )
957 font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
960 mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
965 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
967 // First look into the cache if there is an ellipsis glyph for the requested point size.
968 for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
969 endIt = mEllipsisCache.End();
973 const EllipsisItem& item = *it;
975 if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
977 // Use the glyph in the cache.
982 // No glyph has been found. Create one.
983 mEllipsisCache.PushBack( EllipsisItem() );
984 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
986 item.requestedPointSize = requestedPointSize;
988 // Find a font for the ellipsis glyph.
989 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
993 // Set the character index to access the glyph inside the font.
994 item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
995 ELLIPSIS_CHARACTER );
997 GetBitmapMetrics( &item.glyph, 1u, true );
1002 void FontClient::Plugin::InitSystemFonts()
1004 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
1006 FcFontSet* fontSet = GetFcFontSet();
1010 // Reserve some space to avoid reallocations.
1011 mSystemFonts.reserve( fontSet->nfont );
1013 for( int i = 0u; i < fontSet->nfont; ++i )
1015 FcPattern* fontPattern = fontSet->fonts[i];
1019 // Skip fonts with no path
1020 if( GetFcString( fontPattern, FC_FILE, path ) )
1022 mSystemFonts.push_back( FontDescription() );
1023 FontDescription& fontDescription = mSystemFonts.back();
1025 fontDescription.path = path;
1030 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1031 GetFcInt( fontPattern, FC_WIDTH, width );
1032 GetFcInt( fontPattern, FC_WEIGHT, weight );
1033 GetFcInt( fontPattern, FC_SLANT, slant );
1034 fontDescription.width = IntToWidthType( width );
1035 fontDescription.weight = IntToWeightType( weight );
1036 fontDescription.slant = IntToSlantType( slant );
1037 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
1042 FcFontSetDestroy( fontSet );
1046 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription )
1048 FcResult result = FcResultMatch;
1049 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1058 GetFcString( match, FC_FILE, fontDescription.path );
1059 GetFcString( match, FC_FAMILY, fontDescription.family );
1060 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str());
1061 GetFcInt( match, FC_WIDTH, width );
1062 GetFcInt( match, FC_WEIGHT, weight );
1063 GetFcInt( match, FC_SLANT, slant );
1064 fontDescription.width = IntToWidthType( width );
1065 fontDescription.weight = IntToWeightType( weight );
1066 fontDescription.slant = IntToSlantType( slant );
1068 // destroyed the matched pattern
1069 FcPatternDestroy( match );
1076 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
1078 // create the cached font family lookup pattern
1079 // a pattern holds a set of names, each name refers to a property of the font
1080 FcPattern* fontFamilyPattern = FcPatternCreate();
1082 // add a property to the pattern for the font family
1083 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1085 int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1089 width = DEFAULT_FONT_WIDTH;
1092 int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1096 weight = DEFAULT_FONT_WEIGHT;
1099 int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1103 slant = DEFAULT_FONT_SLANT;
1106 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1107 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1108 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1110 // Add a property of the pattern, to say we want to match TrueType fonts
1111 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1113 // modify the config, with the mFontFamilyPatterm
1114 FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1116 // provide default values for unspecified properties in the font pattern
1117 // e.g. patterns without a specified style or weight are set to Medium
1118 FcDefaultSubstitute( fontFamilyPattern );
1120 return fontFamilyPattern;
1123 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1125 // create a new pattern.
1126 // a pattern holds a set of names, each name refers to a property of the font
1127 FcPattern* pattern = FcPatternCreate();
1129 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1130 FcObjectSet* objectSet = FcObjectSetCreate();
1132 // build an object set from a list of property names
1133 FcObjectSetAdd( objectSet, FC_FILE );
1134 FcObjectSetAdd( objectSet, FC_FAMILY );
1135 FcObjectSetAdd( objectSet, FC_WIDTH );
1136 FcObjectSetAdd( objectSet, FC_WEIGHT );
1137 FcObjectSetAdd( objectSet, FC_SLANT );
1139 // get a list of fonts
1140 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1141 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1143 // clear up the object set
1146 FcObjectSetDestroy( objectSet );
1148 // clear up the pattern
1151 FcPatternDestroy( pattern );
1157 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1158 const char* const n,
1159 std::string& string )
1161 FcChar8* file = NULL;
1162 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1164 if( FcResultMatch == retVal )
1166 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1167 string.assign( reinterpret_cast<const char*>( file ) );
1175 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1177 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1179 if( FcResultMatch == retVal )
1187 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1188 PointSize26Dot6 requestedPointSize,
1189 PointSize26Dot6 actualPointSize,
1190 FaceIndex faceIndex,
1191 bool cacheDescription )
1195 // Create & cache new font face
1197 int error = FT_New_Face( mFreeTypeLibrary,
1202 if( FT_Err_Ok == error )
1204 // Check to see if the font contains fixed sizes?
1205 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1207 // Ensure this size is available
1208 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1210 if ( static_cast<FT_Pos>( actualPointSize ) == ftFace->available_sizes[ i ].size )
1212 // Tell Freetype to use this size
1213 error = FT_Select_Size( ftFace, i );
1214 if ( FT_Err_Ok != error )
1216 DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1220 float fixedWidth = static_cast< float >( ftFace->available_sizes[ i ].width );
1221 float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1223 // Indicate that the font is a fixed sized bitmap
1224 FontMetrics metrics( fixedHeight, // The ascender in pixels.
1226 fixedHeight, // The height in pixels.
1230 mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1231 id = mFontCache.size();
1233 if( cacheDescription )
1235 CacheFontPath( ftFace, id, requestedPointSize, path );
1243 // Can't find this size
1244 std::stringstream sizes;
1245 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1251 sizes << ftFace->available_sizes[ i ].size;
1253 DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1254 path.c_str(), actualPointSize, sizes.str().c_str() );
1258 error = FT_Set_Char_Size( ftFace,
1264 if( FT_Err_Ok == error )
1267 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1269 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1270 static_cast< float >( ftMetrics.descender ) * FROM_266,
1271 static_cast< float >( ftMetrics.height ) * FROM_266,
1272 static_cast< float >( ftFace->underline_position ) * FROM_266,
1273 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1275 mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1276 id = mFontCache.size();
1278 if( cacheDescription )
1280 CacheFontPath( ftFace, id, requestedPointSize, path );
1285 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, actualPointSize );
1291 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1297 void FontClient::Plugin::ConvertBitmap( PixelData& destBitmap,
1298 FT_Bitmap srcBitmap )
1300 if( srcBitmap.width*srcBitmap.rows > 0 )
1302 switch( srcBitmap.pixel_mode )
1304 case FT_PIXEL_MODE_GRAY:
1306 if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
1308 unsigned int bufferSize( srcBitmap.width * srcBitmap.rows );
1309 unsigned char* buffer = new unsigned char[bufferSize];
1310 memcpy( buffer, srcBitmap.buffer,bufferSize );
1311 destBitmap = PixelData::New( buffer, bufferSize, srcBitmap.width, srcBitmap.rows, Pixel::L8, PixelData::DELETE_ARRAY );
1316 #ifdef FREETYPE_BITMAP_SUPPORT
1317 case FT_PIXEL_MODE_BGRA:
1319 if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1321 unsigned int bufferSize( srcBitmap.width * srcBitmap.rows * 4 );
1322 unsigned char* buffer = new unsigned char[bufferSize];
1323 memcpy( buffer, srcBitmap.buffer,bufferSize );
1324 destBitmap = PixelData::New( buffer, bufferSize, srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888, PixelData::DELETE_ARRAY );
1331 DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1338 bool FontClient::Plugin::FindFont( const FontPath& path,
1339 PointSize26Dot6 requestedPointSize,
1340 FaceIndex faceIndex,
1341 FontId& fontId ) const
1344 for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1345 endIt = mFontCache.end();
1349 const FontFaceCacheItem& cacheItem = *it;
1351 if( cacheItem.mRequestedPointSize == requestedPointSize &&
1352 cacheItem.mFaceIndex == faceIndex &&
1353 cacheItem.mPath == path )
1363 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1364 FontDescriptionId& validatedFontId )
1366 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1368 validatedFontId = 0u;
1370 for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1371 endIt = mValidatedFontCache.end();
1375 const FontDescriptionCacheItem& item = *it;
1377 if( !fontDescription.family.empty() &&
1378 ( fontDescription.family == item.fontDescription.family ) &&
1379 ( fontDescription.width == item.fontDescription.width ) &&
1380 ( fontDescription.weight == item.fontDescription.weight ) &&
1381 ( fontDescription.slant == item.fontDescription.slant ) )
1383 validatedFontId = item.index;
1385 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1391 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1396 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1397 FontList*& fontList )
1399 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1403 for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1407 const FallbackCacheItem& item = *it;
1409 if( !fontDescription.family.empty() &&
1410 ( fontDescription.family == item.fontDescription.family ) &&
1411 ( fontDescription.width == item.fontDescription.width ) &&
1412 ( fontDescription.weight == item.fontDescription.weight ) &&
1413 ( fontDescription.slant == item.fontDescription.slant ) )
1415 fontList = item.fallbackFonts;
1417 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1423 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1428 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1429 PointSize26Dot6 requestedPointSize,
1434 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1435 endIt = mFontIdCache.end();
1439 const FontIdCacheItem& item = *it;
1441 if( ( validatedFontId == item.validatedFontId ) &&
1442 ( requestedPointSize == item.requestedPointSize ) )
1444 fontId = item.fontId;
1452 bool FontClient::Plugin::IsScalable( const FontPath& path )
1455 int error = FT_New_Face( mFreeTypeLibrary,
1459 if( FT_Err_Ok != error )
1461 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1463 return ( ftFace->num_fixed_sizes == 0 );
1466 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1468 // Create a font pattern.
1469 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1471 FcResult result = FcResultMatch;
1473 // match the pattern
1474 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1475 bool isScalable = true;
1479 // Get the path to the font file name.
1481 GetFcString( match, FC_FILE, path );
1482 isScalable = IsScalable( path );
1486 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1487 fontDescription.family.c_str(),
1488 fontDescription.width,
1489 fontDescription.weight,
1490 fontDescription.slant );
1492 FcPatternDestroy( fontFamilyPattern );
1493 FcPatternDestroy( match );
1497 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1499 // Empty the caller container
1503 int error = FT_New_Face( mFreeTypeLibrary,
1507 if( FT_Err_Ok != error )
1509 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1512 // Fetch the number of fixed sizes available
1513 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1515 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1517 sizes.PushBack( ftFace->available_sizes[ i ].size );
1522 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1523 Vector< PointSize26Dot6 >& sizes )
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 );
1535 // Get the path to the font file name.
1537 GetFcString( match, FC_FILE, path );
1538 GetFixedSizes( path, sizes );
1542 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1543 fontDescription.family.c_str(),
1544 fontDescription.width,
1545 fontDescription.weight,
1546 fontDescription.slant );
1548 FcPatternDestroy( match );
1549 FcPatternDestroy( fontFamilyPattern );
1552 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path )
1554 FontDescription description;
1555 description.path = path;
1556 description.family = FontFamily( ftFace->family_name );
1557 description.weight = FontWeight::NONE;
1558 description.width = FontWidth::NONE;
1559 description.slant = FontSlant::NONE;
1561 // Note FreeType doesn't give too much info to build a proper font style.
1562 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1564 description.slant = FontSlant::ITALIC;
1566 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1568 description.weight = FontWeight::BOLD;
1571 FontDescriptionId validatedFontId = 0u;
1572 if( !FindValidatedFont( description,
1575 // Set the index to the vector of paths to font file names.
1576 validatedFontId = mFontDescriptionCache.size();
1578 // Add the path to the cache.
1579 mFontDescriptionCache.push_back( description );
1581 // Cache the index and the font's description.
1582 FontDescriptionCacheItem item( description,
1585 mValidatedFontCache.push_back( item );
1587 // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1588 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1594 } // namespace Internal
1596 } // namespace TextAbstraction