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::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
176 FontDescriptionId index )
177 : fontDescription( fontDescription ),
182 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
183 PointSize26Dot6 pointSize,
185 : validatedFontId( validatedFontId ),
186 pointSize( pointSize ),
191 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
192 const FontPath& path,
193 PointSize26Dot6 pointSize,
195 const FontMetrics& metrics )
196 : mFreeTypeFace( ftFace ),
198 mPointSize( pointSize ),
201 mFixedWidthPixels( 0.0f ),
202 mFixedHeightPixels( 0.0f ),
203 mIsFixedSizeBitmap( false )
207 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
208 const FontPath& path,
209 PointSize26Dot6 pointSize,
211 const FontMetrics& metrics,
214 : mFreeTypeFace( ftFace ),
216 mPointSize( pointSize ),
219 mFixedWidthPixels( fixedWidth ),
220 mFixedHeightPixels( fixedHeight ),
221 mIsFixedSizeBitmap( true )
225 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
226 unsigned int verticalDpi )
227 : mFreeTypeLibrary( NULL ),
228 mDpiHorizontal( horizontalDpi ),
229 mDpiVertical( verticalDpi ),
233 mValidatedFontCache(),
234 mFontDescriptionCache( 1u ),
238 int error = FT_Init_FreeType( &mFreeTypeLibrary );
239 if( FT_Err_Ok != error )
241 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
245 FontClient::Plugin::~Plugin()
247 FT_Done_FreeType( mFreeTypeLibrary );
250 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
251 unsigned int verticalDpi )
253 mDpiHorizontal = horizontalDpi;
254 mDpiVertical = verticalDpi;
257 void FontClient::Plugin::SetDefaultFont( const FontDescription& fontDescription )
259 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetDefaultFont family(%s)\n", fontDescription.family.c_str() );
261 mDefaultFonts.clear();
263 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
265 FcResult result = FcResultMatch;
267 // Match the pattern.
268 FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
270 false /* don't trim */,
274 if( NULL != fontSet )
276 // Reserve some space to avoid reallocations.
277 mDefaultFonts.reserve( fontSet->nfont );
279 for( int i = 0u; i < fontSet->nfont; ++i )
281 FcPattern* fontPattern = fontSet->fonts[i];
285 // Skip fonts with no path
286 if( GetFcString( fontPattern, FC_FILE, path ) )
288 mDefaultFonts.push_back( FontDescription() );
289 FontDescription& newFontDescription = mDefaultFonts.back();
291 newFontDescription.path = path;
296 GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
297 GetFcInt( fontPattern, FC_WIDTH, width );
298 GetFcInt( fontPattern, FC_WEIGHT, weight );
299 GetFcInt( fontPattern, FC_SLANT, slant );
300 newFontDescription.width = IntToWidthType( width );
301 newFontDescription.weight = IntToWeightType( weight );
302 newFontDescription.slant = IntToSlantType( slant );
306 FcFontSetDestroy( fontSet );
309 FcPatternDestroy( fontFamilyPattern );
312 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
314 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
316 if( mDefaultFonts.empty() )
318 FontDescription fontDescription;
319 fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
320 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
321 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
322 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
323 SetDefaultFont( fontDescription );
326 defaultFonts = mDefaultFonts;
329 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
331 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
333 if ( Adaptor::IsAvailable() )
335 std::string weight; // todo convert weight into enum
336 Dali::Internal::Adaptor::Adaptor& adaptorImpl( Dali::Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ) );
337 adaptorImpl.GetPlatformAbstraction().GetDefaultFontDescription( fontDescription.family, weight );
338 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription Retreived fontFamily:%s\n", fontDescription.family.c_str() );
342 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
344 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
346 if( mSystemFonts.empty() )
351 systemFonts = mSystemFonts;
354 void FontClient::Plugin::GetDescription( FontId id,
355 FontDescription& fontDescription ) const
357 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
358 endIt = mFontIdCache.end();
362 const FontIdCacheItem& item = *it;
364 if( item.fontId == id )
366 fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
371 DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
374 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
376 const FontId index = id - 1u;
379 index < mFontCache.size() )
381 return ( *( mFontCache.begin() + index ) ).mPointSize;
385 DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
388 return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
391 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
392 PointSize26Dot6 requestedSize,
395 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
398 bool foundColor(false);
400 // Create the list of default fonts if it has not been created.
401 if( mDefaultFonts.empty() )
403 FontDescription fontDescription;
404 fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
405 fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
406 fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
407 fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
408 SetDefaultFont( fontDescription );
411 // Traverse the list of default fonts.
412 // Check for each default font if supports the character.
414 for( FontList::const_iterator it = mDefaultFonts.begin(), endIt = mDefaultFonts.end();
418 const FontDescription& description = *it;
420 FcPattern* pattern = CreateFontFamilyPattern( description );
422 FcResult result = FcResultMatch;
423 FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
425 FcCharSet* charSet = NULL;
426 FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
428 if( FcCharSetHasChar( charSet, charcode ) )
430 Vector< PointSize26Dot6 > fixedSizes;
431 GetFixedSizes( description,
434 const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
437 // If the font is not scalable, pick the largest size <= requestedSize
438 PointSize26Dot6 size = fixedSizes[0];
439 for( unsigned int i=1; i<count; ++i )
441 if( fixedSizes[i] <= requestedSize &&
442 fixedSizes[i] > size )
444 size = fixedSizes[i];
447 requestedSize = size;
450 fontId = GetFontId( description,
456 BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
458 Pixel::BGRA8888 == bitmap.GetPixelFormat() )
464 // Keep going unless we prefer a different (color) font
465 if( !preferColor || foundColor )
467 FcPatternDestroy( match );
468 FcPatternDestroy( pattern );
473 FcPatternDestroy( match );
474 FcPatternDestroy( pattern );
479 FontId FontClient::Plugin::GetFontId( const FontPath& path,
480 PointSize26Dot6 pointSize,
482 bool cacheDescription )
484 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
488 if( NULL != mFreeTypeLibrary )
491 if( FindFont( path, pointSize, faceIndex, foundId ) )
497 id = CreateFont( path, pointSize, faceIndex, cacheDescription );
504 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
505 PointSize26Dot6 pointSize,
506 FaceIndex faceIndex )
508 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() );
510 // This method uses three vectors which caches:
511 // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
512 // * The path to font file names.
513 // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
515 // 1) Checks in the cache if the font's description has been validated before.
516 // If it was it gets an index to the vector with paths to font file names. Otherwise,
517 // retrieves using font config a path to a font file name which matches with the
518 // font's description. The path is stored in the cache.
520 // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
521 // font file names' exists. If exists, it gets the font id. If it doesn't it calls
522 // the GetFontId() method with the path to the font file name and the point size to
525 // The font id to be returned.
528 // Check first if the font's description have been validated before.
529 FontDescriptionId validatedFontId = 0u;
531 if( !FindValidatedFont( fontDescription,
534 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n");
536 // Use font config to validate the font's description.
537 ValidateFont( fontDescription,
541 // Check if exists a pair 'validatedFontId, pointSize' in the cache.
542 if( !FindFont( validatedFontId, pointSize, fontId ) )
544 // Retrieve the font file name path.
545 const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
547 // Retrieve the font id. Do not cache the description as it has been already cached.
548 fontId = GetFontId( description.path,
553 // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
554 mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
562 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
563 FontDescriptionId& validatedFontId )
565 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
567 // Create a font pattern.
568 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
570 FcResult result = FcResultMatch;
573 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
577 // Get the path to the font file name.
581 FontDescription description;
582 GetFcString( match, FC_FILE, description.path );
583 GetFcString( match, FC_FAMILY, description.family );
584 GetFcInt( match, FC_WIDTH, width );
585 GetFcInt( match, FC_WEIGHT, weight );
586 GetFcInt( match, FC_SLANT, slant );
587 description.width = IntToWidthType( width );
588 description.weight = IntToWeightType( weight );
589 description.slant = IntToSlantType( slant );
591 // Set the index to the vector of paths to font file names.
592 validatedFontId = mFontDescriptionCache.size();
594 // Add the path to the cache.
595 mFontDescriptionCache.push_back( description );
597 // Cache the index and the font's description.
598 FontDescriptionCacheItem item( description,
601 mValidatedFontCache.push_back( item );
603 // destroyed the matched pattern
604 FcPatternDestroy( match );
608 DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
609 fontDescription.family.c_str(),
610 fontDescription.width,
611 fontDescription.weight,
612 fontDescription.slant );
615 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() );
617 // destroy the pattern
618 FcPatternDestroy( fontFamilyPattern );
621 void FontClient::Plugin::GetFontMetrics( FontId fontId,
622 FontMetrics& metrics,
626 fontId-1 < mFontCache.size() )
628 const CacheItem& font = mFontCache[fontId-1];
630 metrics = font.mMetrics;
632 // Adjust the metrics if the fixed-size font should be down-scaled
633 if( font.mIsFixedSizeBitmap &&
634 ( maxFixedSize > 0 ) &&
635 ( font.mFixedHeightPixels > maxFixedSize ) )
637 float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
639 metrics.ascender *= scaleFactor;
640 metrics.descender *= scaleFactor;
641 metrics.height *= scaleFactor;
642 metrics.underlinePosition *= scaleFactor;
643 metrics.underlineThickness *= scaleFactor;
648 DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
652 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
655 GlyphIndex index( 0 );
658 fontId-1 < mFontCache.size() )
660 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
662 index = FT_Get_Char_Index( ftFace, charcode );
668 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
673 bool success( true );
675 for( unsigned int i=0; i<size; ++i )
677 FontId fontId = array[i].fontId;
680 fontId-1 < mFontCache.size() )
682 const CacheItem& font = mFontCache[fontId-1];
684 FT_Face ftFace = font.mFreeTypeFace;
686 #ifdef FREETYPE_BITMAP_SUPPORT
687 // Check to see if we should be loading a Fixed Size bitmap?
688 if ( font.mIsFixedSizeBitmap )
690 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
691 if ( FT_Err_Ok == error )
693 array[i].width = font.mFixedWidthPixels;
694 array[i].height = font.mFixedHeightPixels;
695 array[i].advance = font.mFixedWidthPixels;
696 array[i].xBearing = 0.0f;
697 array[i].yBearing = font.mFixedHeightPixels;
699 // Adjust the metrics if the fixed-size font should be down-scaled
700 if( ( maxFixedSize > 0 ) &&
701 ( font.mFixedHeightPixels > maxFixedSize ) )
703 float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
705 array[i].width *= scaleFactor;
706 array[i].height *= scaleFactor;
707 array[i].advance *= scaleFactor;
708 array[i].xBearing *= scaleFactor;
709 array[i].yBearing *= scaleFactor;
711 array[i].scaleFactor = scaleFactor;
716 DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
723 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
725 if( FT_Err_Ok == error )
727 array[i].width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
728 array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
731 array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
732 array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
736 array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
737 array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
755 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
756 GlyphIndex glyphIndex )
761 fontId-1 < mFontCache.size() )
763 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
767 #ifdef FREETYPE_BITMAP_SUPPORT
768 // Check to see if this is fixed size bitmap
769 if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
771 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
776 error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
778 if( FT_Err_Ok == error )
781 error = FT_Get_Glyph( ftFace->glyph, &glyph );
783 // Convert to bitmap if necessary
784 if ( FT_Err_Ok == error )
786 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
788 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
789 if ( FT_Err_Ok == error )
791 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
792 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
796 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
801 ConvertBitmap( bitmap, ftFace->glyph->bitmap );
804 // Created FT_Glyph object must be released with FT_Done_Glyph
805 FT_Done_Glyph( glyph );
810 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
817 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
819 // First look into the cache if there is an ellipsis glyph for the requested point size.
820 for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
821 endIt = mEllipsisCache.End();
825 const EllipsisItem& item = *it;
827 if( fabsf( item.size - pointSize ) < Math::MACHINE_EPSILON_1000 )
829 // Use the glyph in the cache.
834 // No glyph has been found. Create one.
835 mEllipsisCache.PushBack( EllipsisItem() );
836 EllipsisItem& item = *( mEllipsisCache.End() - 1u );
838 item.size = pointSize;
840 // Find a font for the ellipsis glyph.
841 item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
845 // Set the character index to access the glyph inside the font.
846 item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
847 ELLIPSIS_CHARACTER );
849 GetGlyphMetrics( &item.glyph, 1u, true, 0 );
854 void FontClient::Plugin::InitSystemFonts()
856 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
858 FcFontSet* fontSet = GetFcFontSet();
862 // Reserve some space to avoid reallocations.
863 mSystemFonts.reserve( fontSet->nfont );
865 for( int i = 0u; i < fontSet->nfont; ++i )
867 FcPattern* fontPattern = fontSet->fonts[i];
871 // Skip fonts with no path
872 if( GetFcString( fontPattern, FC_FILE, path ) )
874 mSystemFonts.push_back( FontDescription() );
875 FontDescription& fontDescription = mSystemFonts.back();
877 fontDescription.path = path;
882 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
883 GetFcInt( fontPattern, FC_WIDTH, width );
884 GetFcInt( fontPattern, FC_WEIGHT, weight );
885 GetFcInt( fontPattern, FC_SLANT, slant );
886 fontDescription.width = IntToWidthType( width );
887 fontDescription.weight = IntToWeightType( weight );
888 fontDescription.slant = IntToSlantType( slant );
889 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
894 FcFontSetDestroy( fontSet );
898 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
900 // create the cached font family lookup pattern
901 // a pattern holds a set of names, each name refers to a property of the font
902 FcPattern* fontFamilyPattern = FcPatternCreate();
904 // add a property to the pattern for the font family
905 FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
907 FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, FONT_WIDTH_TYPE_TO_INT[fontDescription.width] );
908 FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight] );
909 FcPatternAddInteger( fontFamilyPattern, FC_SLANT, FONT_SLANT_TYPE_TO_INT[fontDescription.slant] );
911 // Add a property of the pattern, to say we want to match TrueType fonts
912 FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
914 // modify the config, with the mFontFamilyPatterm
915 FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
917 // provide default values for unspecified properties in the font pattern
918 // e.g. patterns without a specified style or weight are set to Medium
919 FcDefaultSubstitute( fontFamilyPattern );
921 return fontFamilyPattern;
924 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
926 // create a new pattern.
927 // a pattern holds a set of names, each name refers to a property of the font
928 FcPattern* pattern = FcPatternCreate();
930 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
931 FcObjectSet* objectSet = FcObjectSetCreate();
933 // build an object set from a list of property names
934 FcObjectSetAdd( objectSet, FC_FILE );
935 FcObjectSetAdd( objectSet, FC_FAMILY );
936 FcObjectSetAdd( objectSet, FC_WIDTH );
937 FcObjectSetAdd( objectSet, FC_WEIGHT );
938 FcObjectSetAdd( objectSet, FC_SLANT );
940 // get a list of fonts
941 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
942 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
944 // clear up the object set
947 FcObjectSetDestroy( objectSet );
949 // clear up the pattern
952 FcPatternDestroy( pattern );
958 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
960 std::string& string )
962 FcChar8* file = NULL;
963 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
965 if( FcResultMatch == retVal )
967 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
968 string.assign( reinterpret_cast<const char*>( file ) );
976 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
978 const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
980 if( FcResultMatch == retVal )
988 FontId FontClient::Plugin::CreateFont( const FontPath& path,
989 PointSize26Dot6 pointSize,
991 bool cacheDescription )
995 // Create & cache new font face
997 int error = FT_New_Face( mFreeTypeLibrary,
1002 if( FT_Err_Ok == error )
1004 // Check to see if the font contains fixed sizes?
1005 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1007 // Ensure this size is available
1008 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1010 if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
1012 // Tell Freetype to use this size
1013 error = FT_Select_Size( ftFace, i );
1014 if ( FT_Err_Ok != error )
1016 DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1020 float fixedWidth = static_cast< float >( ftFace->available_sizes[ i ].width );
1021 float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1023 // Indicate that the font is a fixed sized bitmap
1024 FontMetrics metrics( fixedHeight, // The ascender in pixels.
1026 fixedHeight, // The height in pixels.
1030 mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1031 id = mFontCache.size();
1033 if( cacheDescription )
1035 FontDescription description;
1036 description.path = path;
1037 description.family = FontFamily( ftFace->family_name );
1039 // Note FreeType doesn't give too much info to build a proper font style.
1040 if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1042 description.slant = FontSlant::ITALIC;
1044 if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1046 description.weight = FontWeight::BOLD;
1049 mFontDescriptionCache.push_back( description );
1056 // Can't find this size
1057 std::stringstream sizes;
1058 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1064 sizes << ftFace->available_sizes[ i ].size;
1066 DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1067 path.c_str(), pointSize, sizes.str().c_str() );
1071 error = FT_Set_Char_Size( ftFace,
1077 if( FT_Err_Ok == error )
1080 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1082 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
1083 static_cast< float >( ftMetrics.descender ) * FROM_266,
1084 static_cast< float >( ftMetrics.height ) * FROM_266,
1085 static_cast< float >( ftFace->underline_position ) * FROM_266,
1086 static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1088 mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
1089 id = mFontCache.size();
1091 if( cacheDescription )
1093 FontDescription description;
1094 description.path = path;
1095 description.family = FontFamily( ftFace->family_name );
1097 // Note FreeType doesn't give too much info to build a proper font style.
1098 if( ftFace->style_flags | FT_STYLE_FLAG_ITALIC )
1100 description.slant = FontSlant::ITALIC;
1102 if( ftFace->style_flags | FT_STYLE_FLAG_BOLD )
1104 description.weight = FontWeight::BOLD;
1107 mFontDescriptionCache.push_back( description );
1112 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
1118 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1124 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
1125 FT_Bitmap srcBitmap )
1127 if( srcBitmap.width*srcBitmap.rows > 0 )
1129 switch( srcBitmap.pixel_mode )
1131 case FT_PIXEL_MODE_GRAY:
1133 if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
1135 destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
1137 PixelBuffer* destBuffer = destBitmap.GetBuffer();
1140 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
1144 DALI_LOG_ERROR( "GetBuffer returns null\n" );
1150 #ifdef FREETYPE_BITMAP_SUPPORT
1151 case FT_PIXEL_MODE_BGRA:
1153 if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
1155 destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
1157 PixelBuffer* destBuffer = destBitmap.GetBuffer();
1160 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
1164 DALI_LOG_ERROR( "GetBuffer returns null\n" );
1172 DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1179 bool FontClient::Plugin::FindFont( const FontPath& path,
1180 PointSize26Dot6 pointSize,
1181 FaceIndex faceIndex,
1182 FontId& fontId ) const
1185 for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
1186 endIt = mFontCache.end();
1190 const CacheItem& cacheItem = *it;
1192 if( cacheItem.mPointSize == pointSize &&
1193 cacheItem.mFaceIndex == faceIndex &&
1194 cacheItem.mPath == path )
1204 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1205 FontDescriptionId& validatedFontId )
1207 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1209 validatedFontId = 0u;
1211 for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1212 endIt = mValidatedFontCache.end();
1216 const FontDescriptionCacheItem& item = *it;
1218 if( !fontDescription.family.empty() &&
1219 ( fontDescription.family == item.fontDescription.family ) &&
1220 ( fontDescription.width == item.fontDescription.width ) &&
1221 ( fontDescription.weight == item.fontDescription.weight ) &&
1222 ( fontDescription.slant == item.fontDescription.slant ) )
1224 validatedFontId = item.index;
1226 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1232 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1237 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1238 PointSize26Dot6 pointSize,
1243 for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1244 endIt = mFontIdCache.end();
1248 const FontIdCacheItem& item = *it;
1250 if( ( validatedFontId == item.validatedFontId ) &&
1251 ( pointSize == item.pointSize ) )
1253 fontId = item.fontId;
1261 bool FontClient::Plugin::IsScalable( const FontPath& path )
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() );
1272 return ( ftFace->num_fixed_sizes == 0 );
1275 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1277 // Create a font pattern.
1278 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1280 FcResult result = FcResultMatch;
1282 // match the pattern
1283 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1284 bool isScalable = true;
1288 // Get the path to the font file name.
1290 GetFcString( match, FC_FILE, path );
1291 isScalable = IsScalable( path );
1295 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1296 fontDescription.family.c_str(),
1297 fontDescription.width,
1298 fontDescription.weight,
1299 fontDescription.slant );
1301 FcPatternDestroy( fontFamilyPattern );
1302 FcPatternDestroy( match );
1306 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1308 // Empty the caller container
1312 int error = FT_New_Face( mFreeTypeLibrary,
1316 if( FT_Err_Ok != error )
1318 DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1321 // Fetch the number of fixed sizes available
1322 if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1324 for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1326 sizes.PushBack( ftFace->available_sizes[ i ].size );
1331 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1332 Vector< PointSize26Dot6 >& sizes )
1334 // Create a font pattern.
1335 FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1337 FcResult result = FcResultMatch;
1339 // match the pattern
1340 FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1344 // Get the path to the font file name.
1346 GetFcString( match, FC_FILE, path );
1347 GetFixedSizes( path, sizes );
1351 DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1352 fontDescription.family.c_str(),
1353 fontDescription.width,
1354 fontDescription.weight,
1355 fontDescription.slant );
1357 FcPatternDestroy( match );
1358 FcPatternDestroy( fontFamilyPattern );
1361 } // namespace Internal
1363 } // namespace TextAbstraction