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 )
46 : mFreeTypeFace( ftFace ),
48 mPointSize( pointSize ),
53 FT_Face mFreeTypeFace;
55 PointSize26Dot6 mPointSize;
59 Plugin( unsigned int horizontalDpi, unsigned int verticalDpi )
60 : mFreeTypeLibrary( NULL ),
61 mDpiHorizontal( horizontalDpi ),
62 mDpiVertical( verticalDpi )
68 FT_Done_FreeType( mFreeTypeLibrary );
73 int error = FT_Init_FreeType( &mFreeTypeLibrary );
74 if( FT_Err_Ok != error )
76 DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
80 void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
82 mDpiHorizontal = horizontalDpi;
83 mDpiVertical = verticalDpi;
86 void GetSystemFonts( FontList& systemFonts )
88 if( mSystemFonts.empty() )
93 systemFonts = mSystemFonts;
96 void InitSystemFonts()
98 FcFontSet* fontSet = GetFcFontSet();
102 mSystemFonts.reserve( fontSet->nfont );
104 for( int i = 0u; i < fontSet->nfont; ++i )
106 FcPattern* fontPattern = fontSet->fonts[i];
110 // Skip fonts with no path
111 if( GetFcString( fontPattern, FC_FILE, path ) )
113 mSystemFonts.push_back( FontDescription() );
114 FontDescription& fontDescription = mSystemFonts.back();
116 fontDescription.path = path;
118 GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
119 GetFcString( fontPattern, FC_STYLE, fontDescription.style );
123 FcFontSetDestroy( fontSet );
127 _FcFontSet* GetFcFontSet() const
129 // create a new pattern.
130 // a pattern holds a set of names, each name refers to a property of the font
131 FcPattern* pattern = FcPatternCreate();
133 // create an object set used to define which properties are to be returned in the patterns from FcFontList.
134 FcObjectSet* objectSet = FcObjectSetCreate();
136 // build an object set from a list of property names
137 FcObjectSetAdd( objectSet, FC_FILE );
138 FcObjectSetAdd( objectSet, FC_FAMILY );
139 FcObjectSetAdd( objectSet, FC_STYLE );
141 // get a list of fonts
142 // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
143 FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
145 // clear up the object set
148 FcObjectSetDestroy( objectSet );
150 // clear up the pattern
153 FcPatternDestroy( pattern );
159 bool GetFcString( const FcPattern* pattern, const char* n, std::string& string )
161 FcChar8* file = NULL;
162 const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
164 if( FcResultMatch == retVal )
166 // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
167 string.assign( reinterpret_cast<const char*>( file ) );
175 bool FindSystemFont( Character charcode, FontDescription& systemFont )
177 // TODO - Use FcCharSetHasChar()
182 FontId GetFontId( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
186 if( NULL != mFreeTypeLibrary )
189 if( FindFont( path, pointSize, faceIndex, foundId ) )
195 id = CreateFont( path, pointSize, faceIndex );
202 GlyphIndex GetGlyphIndex( FontId fontId, Character charcode )
204 GlyphIndex index( 0 );
207 fontId-1 < mFontCache.size() )
209 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
211 index = FT_Get_Char_Index( ftFace, charcode );
217 FontId CreateFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
221 // Create & cache new font face
223 int error = FT_New_Face( mFreeTypeLibrary,
228 if( FT_Err_Ok == error )
230 error = FT_Set_Char_Size( ftFace,
236 if( FT_Err_Ok == error )
238 id = mFontCache.size() + 1;
239 mFontCache.push_back( CacheItem( id, ftFace, path, pointSize, faceIndex ) );
243 DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", pointSize );
248 DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
254 FontId FindDefaultFont( Character charcode )
256 // TODO - Return cached results based on script
260 bool CreateMetrics( FontId fontId, GlyphMetrics* array, uint32_t size, bool horizontal )
262 bool success( true );
265 fontId-1 < mFontCache.size() )
267 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
269 for( unsigned int i=0; i<size; ++i )
271 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
273 if( FT_Err_Ok == error )
275 array[i].width = ftFace->glyph->metrics.width;
276 array[i].height = ftFace->glyph->metrics.height;
279 array[i].xBearing = ftFace->glyph->metrics.horiBearingX;
280 array[i].yBearing = ftFace->glyph->metrics.horiBearingY;
281 array[i].advance = ftFace->glyph->metrics.horiAdvance;
285 array[i].xBearing = ftFace->glyph->metrics.vertBearingX;
286 array[i].yBearing = ftFace->glyph->metrics.vertBearingY;
287 array[i].advance = ftFace->glyph->metrics.vertAdvance;
300 BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
305 fontId-1 < mFontCache.size() )
307 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
309 FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
310 if( FT_Err_Ok == error )
313 error = FT_Get_Glyph( ftFace->glyph, &glyph );
315 // Convert to bitmap if necessary
316 if ( FT_Err_Ok == error )
318 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
320 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
324 DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
329 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
332 if( FT_Err_Ok == error )
334 // Access the underlying bitmap data
335 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
336 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
339 // Created FT_Glyph object must be released with FT_Done_Glyph
340 FT_Done_Glyph( glyph );
344 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
351 void ConvertBitmap( BitmapImage& destBitmap, FT_Bitmap srcBitmap )
353 if( srcBitmap.width*srcBitmap.rows > 0 )
355 // TODO - Support all pixel modes
356 if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
358 if( srcBitmap.pitch == srcBitmap.width )
360 destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
362 PixelBuffer* destBuffer = destBitmap.GetBuffer();
363 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
371 bool FindFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, FontId& found ) const
373 for( unsigned int i=0; i<mFontCache.size(); ++i )
375 if( mFontCache[i].mPointSize == pointSize &&
376 mFontCache[i].mPath == path &&
377 mFontCache[i].mFaceIndex == faceIndex )
387 FT_Library mFreeTypeLibrary;
389 FontList mSystemFonts;
391 std::vector<CacheItem> mFontCache;
393 unsigned int mDpiHorizontal;
394 unsigned int mDpiVertical;
397 FontClient::FontClient()
404 FontClient::~FontClient()
409 Dali::TextAbstraction::FontClient FontClient::Get()
411 Dali::TextAbstraction::FontClient fontClientHandle;
413 Dali::SingletonService service( SingletonService::Get() );
416 // Check whether the singleton is already created
417 Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
420 // If so, downcast the handle
421 FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
422 fontClientHandle = Dali::TextAbstraction::FontClient( impl );
424 else // create and register the object
426 fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
427 service.Register( typeid( fontClientHandle ), fontClientHandle );
431 return fontClientHandle;
434 void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
436 mDpiHorizontal = horizontalDpi;
437 mDpiVertical = verticalDpi;
439 // Allow DPI to be set without loading plugin
442 mPlugin->SetDpi( horizontalDpi, verticalDpi );
446 void FontClient::GetSystemFonts( FontList& systemFonts )
450 mPlugin->GetSystemFonts( systemFonts );
453 bool FontClient::FindSystemFont( Character charcode, FontDescription& systemFont )
457 return mPlugin->FindSystemFont( charcode, systemFont );
460 FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
464 return mPlugin->GetFontId( path, pointSize, faceIndex );
467 FontId FontClient::FindDefaultFont( Character charcode )
471 return mPlugin->FindDefaultFont( charcode );
474 GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
478 return mPlugin->GetGlyphIndex( fontId, charcode );
481 bool FontClient::CreateMetrics( FontId fontId, GlyphMetrics* array, uint32_t size, bool horizontal )
485 return mPlugin->CreateMetrics( fontId, array, size, horizontal );
488 BitmapImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
492 return mPlugin->CreateBitmap( fontId, glyphIndex );
495 void FontClient::CreatePlugin()
499 mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
500 mPlugin->Initialize();
504 } // namespace Internal
506 } // namespace FontClient