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>
35 namespace TextAbstraction
41 struct FontClient::Plugin
45 CacheItem( FontId id, FT_Face ftFace, const std::string& path, PointSize26Dot6 pointSize, FaceIndex face, const FontMetrics& metrics )
46 : mFreeTypeFace( ftFace ),
48 mPointSize( pointSize ),
54 FT_Face mFreeTypeFace;
56 PointSize26Dot6 mPointSize;
61 Plugin( unsigned int horizontalDpi, unsigned int verticalDpi )
62 : mFreeTypeLibrary( NULL ),
63 mDpiHorizontal( horizontalDpi ),
64 mDpiVertical( verticalDpi )
70 FT_Done_FreeType( mFreeTypeLibrary );
75 int error = FT_Init_FreeType( &mFreeTypeLibrary );
76 if( FT_Err_Ok != error )
78 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
82 void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
84 mDpiHorizontal = horizontalDpi;
85 mDpiVertical = verticalDpi;
88 void GetSystemFonts( FontList& systemFonts )
90 if( mSystemFonts.empty() )
95 systemFonts = mSystemFonts;
98 void InitSystemFonts()
100 FcFontSet* fontSet = GetFcFontSet();
104 mSystemFonts.reserve( fontSet->nfont );
106 for( int i = 0u; i < fontSet->nfont; ++i )
108 FcPattern* fontPattern = fontSet->fonts[i];
112 // Skip fonts with no path
113 if( GetFcString( fontPattern, FC_FILE, path ) )
115 mSystemFonts.push_back( FontDescription() );
116 FontDescription& fontDescription = mSystemFonts.back();
118 fontDescription.path = path;
120 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
121 GetFcString( fontPattern, FC_STYLE, fontDescription.style );
125 FcFontSetDestroy( fontSet );
129 _FcFontSet* GetFcFontSet() const
131 // create a new pattern.
132 // a pattern holds a set of names, each name refers to a property of the font
133 FcPattern* pattern = FcPatternCreate();
135 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
136 FcObjectSet* objectSet = FcObjectSetCreate();
138 // build an object set from a list of property names
139 FcObjectSetAdd( objectSet, FC_FILE );
140 FcObjectSetAdd( objectSet, FC_FAMILY );
141 FcObjectSetAdd( objectSet, FC_STYLE );
143 // get a list of fonts
144 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
145 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
147 // clear up the object set
150 FcObjectSetDestroy( objectSet );
152 // clear up the pattern
155 FcPatternDestroy( pattern );
161 bool GetFcString( const FcPattern* pattern, const char* n, std::string& string )
163 FcChar8* file = NULL;
164 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
166 if( FcResultMatch == retVal )
168 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
169 string.assign( reinterpret_cast<const char*>( file ) );
177 bool FindSystemFont( Character charcode, FontDescription& systemFont )
179 // TODO - Use FcCharSetHasChar()
184 FontId GetFontId( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
188 if( NULL != mFreeTypeLibrary )
191 if( FindFont( path, pointSize, faceIndex, foundId ) )
197 id = CreateFont( path, pointSize, faceIndex );
204 GlyphIndex GetGlyphIndex( FontId fontId, Character charcode )
206 GlyphIndex index( 0 );
209 fontId-1 < mFontCache.size() )
211 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
213 index = FT_Get_Char_Index( ftFace, charcode );
219 FontId CreateFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
223 // Create & cache new font face
225 int error = FT_New_Face( mFreeTypeLibrary,
230 if( FT_Err_Ok == error )
232 error = FT_Set_Char_Size( ftFace,
238 if( FT_Err_Ok == error )
240 id = mFontCache.size() + 1;
242 FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
243 FontMetrics metrics( ftMetrics.ascender, ftMetrics.descender, ftMetrics.height );
245 mFontCache.push_back( CacheItem( id, ftFace, path, pointSize, faceIndex, metrics ) );
249 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", pointSize );
254 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
260 FontId FindDefaultFont( Character charcode )
262 // TODO - Return cached results based on script
266 void GetFontMetrics( FontId fontId, FontMetrics& metrics )
269 fontId-1 < mFontCache.size() )
271 metrics = mFontCache[fontId-1].mMetrics;
275 DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
279 bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
281 bool success( true );
283 for( unsigned int i=0; i<size; ++i )
285 FontId fontId = array[i].fontId;
288 fontId-1 < mFontCache.size() )
290 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
292 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
294 if( FT_Err_Ok == error )
296 array[i].width = ftFace->glyph->metrics.width;
297 array[i].height = ftFace->glyph->metrics.height;
300 array[i].xBearing = ftFace->glyph->metrics.horiBearingX;
301 array[i].yBearing = ftFace->glyph->metrics.horiBearingY;
302 array[i].advance = ftFace->glyph->metrics.horiAdvance;
306 array[i].xBearing = ftFace->glyph->metrics.vertBearingX;
307 array[i].yBearing = ftFace->glyph->metrics.vertBearingY;
308 array[i].advance = ftFace->glyph->metrics.vertAdvance;
325 BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
330 fontId-1 < mFontCache.size() )
332 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
334 FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
335 if( FT_Err_Ok == error )
338 error = FT_Get_Glyph( ftFace->glyph, &glyph );
340 // Convert to bitmap if necessary
341 if ( FT_Err_Ok == error )
343 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
345 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
349 DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
354 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
357 if( FT_Err_Ok == error )
359 // Access the underlying bitmap data
360 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
361 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
364 // Created FT_Glyph object must be released with FT_Done_Glyph
365 FT_Done_Glyph( glyph );
369 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
376 void ConvertBitmap( BitmapImage& destBitmap, FT_Bitmap srcBitmap )
378 if( srcBitmap.width*srcBitmap.rows > 0 )
380 // TODO - Support all pixel modes
381 if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
383 if( srcBitmap.pitch == srcBitmap.width )
385 destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
387 PixelBuffer* destBuffer = destBitmap.GetBuffer();
388 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
396 bool FindFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, FontId& found ) const
398 for( unsigned int i=0; i<mFontCache.size(); ++i )
400 if( mFontCache[i].mPointSize == pointSize &&
401 mFontCache[i].mPath == path &&
402 mFontCache[i].mFaceIndex == faceIndex )
412 FT_Library mFreeTypeLibrary;
414 FontList mSystemFonts;
416 std::vector<CacheItem> mFontCache;
418 unsigned int mDpiHorizontal;
419 unsigned int mDpiVertical;
422 FontClient::FontClient()
429 FontClient::~FontClient()
434 Dali::TextAbstraction::FontClient FontClient::Get()
436 Dali::TextAbstraction::FontClient fontClientHandle;
438 Dali::SingletonService service( SingletonService::Get() );
441 // Check whether the singleton is already created
442 Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
445 // If so, downcast the handle
446 FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
447 fontClientHandle = Dali::TextAbstraction::FontClient( impl );
449 else // create and register the object
451 fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
452 service.Register( typeid( fontClientHandle ), fontClientHandle );
456 return fontClientHandle;
459 void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
461 mDpiHorizontal = horizontalDpi;
462 mDpiVertical = verticalDpi;
464 // Allow DPI to be set without loading plugin
467 mPlugin->SetDpi( horizontalDpi, verticalDpi );
471 void FontClient::GetSystemFonts( FontList& systemFonts )
475 mPlugin->GetSystemFonts( systemFonts );
478 bool FontClient::FindSystemFont( Character charcode, FontDescription& systemFont )
482 return mPlugin->FindSystemFont( charcode, systemFont );
485 FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
489 return mPlugin->GetFontId( path, pointSize, faceIndex );
492 FontId FontClient::FindDefaultFont( Character charcode )
496 return mPlugin->FindDefaultFont( charcode );
499 void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
503 return mPlugin->GetFontMetrics( fontId, metrics );
506 GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
510 return mPlugin->GetGlyphIndex( fontId, charcode );
513 bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
517 return mPlugin->GetGlyphMetrics( array, size, horizontal );
520 BitmapImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
524 return mPlugin->CreateBitmap( fontId, glyphIndex );
527 void FontClient::CreatePlugin()
531 mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
532 mPlugin->Initialize();
536 } // namespace Internal
538 } // namespace FontClient