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 "font-client-impl.h"
24 #include FT_FREETYPE_H
26 #include <fontconfig/fontconfig.h>
27 #include <dali/integration-api/debug.h>
30 #include <singleton-service-impl.h>
33 * Conversion from Fractional26.6 to float
37 const float FROM_266 = 1.0f / 64.0f;
43 namespace TextAbstraction
49 struct FontClient::Plugin
53 CacheItem( FontId id, FT_Face ftFace, const std::string& path, PointSize26Dot6 pointSize, FaceIndex face, const FontMetrics& metrics )
54 : mFreeTypeFace( ftFace ),
56 mPointSize( pointSize ),
62 FT_Face mFreeTypeFace;
64 PointSize26Dot6 mPointSize;
69 Plugin( unsigned int horizontalDpi, unsigned int verticalDpi )
70 : mFreeTypeLibrary( NULL ),
71 mDpiHorizontal( horizontalDpi ),
72 mDpiVertical( verticalDpi )
78 FT_Done_FreeType( mFreeTypeLibrary );
83 int error = FT_Init_FreeType( &mFreeTypeLibrary );
84 if( FT_Err_Ok != error )
86 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
90 void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
92 mDpiHorizontal = horizontalDpi;
93 mDpiVertical = verticalDpi;
96 void GetSystemFonts( FontList& systemFonts )
98 if( mSystemFonts.empty() )
103 systemFonts = mSystemFonts;
106 void InitSystemFonts()
108 FcFontSet* fontSet = GetFcFontSet();
112 mSystemFonts.reserve( fontSet->nfont );
114 for( int i = 0u; i < fontSet->nfont; ++i )
116 FcPattern* fontPattern = fontSet->fonts[i];
120 // Skip fonts with no path
121 if( GetFcString( fontPattern, FC_FILE, path ) )
123 mSystemFonts.push_back( FontDescription() );
124 FontDescription& fontDescription = mSystemFonts.back();
126 fontDescription.path = path;
128 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
129 GetFcString( fontPattern, FC_STYLE, fontDescription.style );
133 FcFontSetDestroy( fontSet );
137 _FcFontSet* GetFcFontSet() const
139 // create a new pattern.
140 // a pattern holds a set of names, each name refers to a property of the font
141 FcPattern* pattern = FcPatternCreate();
143 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
144 FcObjectSet* objectSet = FcObjectSetCreate();
146 // build an object set from a list of property names
147 FcObjectSetAdd( objectSet, FC_FILE );
148 FcObjectSetAdd( objectSet, FC_FAMILY );
149 FcObjectSetAdd( objectSet, FC_STYLE );
151 // get a list of fonts
152 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
153 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
155 // clear up the object set
158 FcObjectSetDestroy( objectSet );
160 // clear up the pattern
163 FcPatternDestroy( pattern );
169 bool GetFcString( const FcPattern* pattern, const char* n, std::string& string )
171 FcChar8* file = NULL;
172 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
174 if( FcResultMatch == retVal )
176 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
177 string.assign( reinterpret_cast<const char*>( file ) );
185 void GetDescription( FontId id, FontDescription& fontDescription ) const
190 PointSize26Dot6 GetPointSize( FontId id )
195 FontId FindDefaultFont( Character charcode, PointSize26Dot6 pointSize )
197 // TODO - Use FcCharSetHasChar()
201 FontId GetFontId( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
205 if( NULL != mFreeTypeLibrary )
208 if( FindFont( path, pointSize, faceIndex, foundId ) )
214 id = CreateFont( path, pointSize, faceIndex );
221 FontId GetFontId( const FontFamily& fontFamily,
222 const FontStyle& fontStyle,
223 PointSize26Dot6 pointSize,
224 FaceIndex faceIndex )
229 GlyphIndex GetGlyphIndex( FontId fontId, Character charcode )
231 GlyphIndex index( 0 );
234 fontId-1 < mFontCache.size() )
236 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
238 index = FT_Get_Char_Index( ftFace, charcode );
244 FontId CreateFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
248 // Create & cache new font face
250 int error = FT_New_Face( mFreeTypeLibrary,
255 if( FT_Err_Ok == error )
257 error = FT_Set_Char_Size( ftFace,
263 if( FT_Err_Ok == error )
265 id = mFontCache.size() + 1;
267 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
269 FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
270 static_cast< float >( ftMetrics.descender ) * FROM_266,
271 static_cast< float >( ftMetrics.height ) * FROM_266 );
273 mFontCache.push_back( CacheItem( id, ftFace, path, pointSize, faceIndex, metrics ) );
277 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", pointSize );
282 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
288 void GetFontMetrics( FontId fontId, FontMetrics& metrics )
291 fontId-1 < mFontCache.size() )
293 metrics = mFontCache[fontId-1].mMetrics;
297 DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
301 bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
303 bool success( true );
305 for( unsigned int i=0; i<size; ++i )
307 FontId fontId = array[i].fontId;
310 fontId-1 < mFontCache.size() )
312 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
314 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
316 if( FT_Err_Ok == error )
318 array[i].width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
319 array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
322 array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
323 array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
324 array[i].advance = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
328 array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
329 array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
330 array[i].advance = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
347 BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
352 fontId-1 < mFontCache.size() )
354 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
356 FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
357 if( FT_Err_Ok == error )
360 error = FT_Get_Glyph( ftFace->glyph, &glyph );
362 // Convert to bitmap if necessary
363 if ( FT_Err_Ok == error )
365 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
367 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
371 DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
376 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
379 if( FT_Err_Ok == error )
381 // Access the underlying bitmap data
382 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
383 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
386 // Created FT_Glyph object must be released with FT_Done_Glyph
387 FT_Done_Glyph( glyph );
391 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
398 void ConvertBitmap( BitmapImage& destBitmap, FT_Bitmap srcBitmap )
400 if( srcBitmap.width*srcBitmap.rows > 0 )
402 // TODO - Support all pixel modes
403 if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
405 if( srcBitmap.pitch == srcBitmap.width )
407 destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
409 PixelBuffer* destBuffer = destBitmap.GetBuffer();
410 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
418 bool FindFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, FontId& found ) const
420 for( unsigned int i=0; i<mFontCache.size(); ++i )
422 if( mFontCache[i].mPointSize == pointSize &&
423 mFontCache[i].mPath == path &&
424 mFontCache[i].mFaceIndex == faceIndex )
434 FT_Library mFreeTypeLibrary;
436 FontList mSystemFonts;
438 std::vector<CacheItem> mFontCache;
440 unsigned int mDpiHorizontal;
441 unsigned int mDpiVertical;
444 FontClient::FontClient()
451 FontClient::~FontClient()
456 Dali::TextAbstraction::FontClient FontClient::Get()
458 Dali::TextAbstraction::FontClient fontClientHandle;
460 Dali::SingletonService service( SingletonService::Get() );
463 // Check whether the singleton is already created
464 Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
467 // If so, downcast the handle
468 FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
469 fontClientHandle = Dali::TextAbstraction::FontClient( impl );
471 else // create and register the object
473 fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
474 service.Register( typeid( fontClientHandle ), fontClientHandle );
478 return fontClientHandle;
481 void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
483 mDpiHorizontal = horizontalDpi;
484 mDpiVertical = verticalDpi;
486 // Allow DPI to be set without loading plugin
489 mPlugin->SetDpi( horizontalDpi, verticalDpi );
493 void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
498 PointSize26Dot6 FontClient::GetPointSize( FontId id )
502 return mPlugin->GetPointSize( id );
505 void FontClient::GetSystemFonts( FontList& systemFonts )
509 mPlugin->GetSystemFonts( systemFonts );
512 FontId FontClient::FindDefaultFont( Character charcode, PointSize26Dot6 pointSize )
516 return mPlugin->FindDefaultFont( charcode, pointSize );
519 FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
523 return mPlugin->GetFontId( path, pointSize, faceIndex );
526 FontId FontClient::GetFontId( const FontFamily& fontFamily,
527 const FontStyle& fontStyle,
528 PointSize26Dot6 pointSize,
529 FaceIndex faceIndex )
533 return mPlugin->GetFontId( fontFamily,
539 void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
543 return mPlugin->GetFontMetrics( fontId, metrics );
546 GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
550 return mPlugin->GetGlyphIndex( fontId, charcode );
553 bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
557 return mPlugin->GetGlyphMetrics( array, size, horizontal );
560 BitmapImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
564 return mPlugin->CreateBitmap( fontId, glyphIndex );
567 void FontClient::CreatePlugin()
571 mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
572 mPlugin->Initialize();
576 } // namespace Internal
578 } // namespace FontClient