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 GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
262 bool success( true );
264 for( unsigned int i=0; i<size; ++i )
266 FontId fontId = array[i].fontId;
269 fontId-1 < mFontCache.size() )
271 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
273 int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
275 if( FT_Err_Ok == error )
277 array[i].width = ftFace->glyph->metrics.width;
278 array[i].height = ftFace->glyph->metrics.height;
281 array[i].xBearing = ftFace->glyph->metrics.horiBearingX;
282 array[i].yBearing = ftFace->glyph->metrics.horiBearingY;
283 array[i].advance = ftFace->glyph->metrics.horiAdvance;
287 array[i].xBearing = ftFace->glyph->metrics.vertBearingX;
288 array[i].yBearing = ftFace->glyph->metrics.vertBearingY;
289 array[i].advance = ftFace->glyph->metrics.vertAdvance;
306 BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
311 fontId-1 < mFontCache.size() )
313 FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
315 FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
316 if( FT_Err_Ok == error )
319 error = FT_Get_Glyph( ftFace->glyph, &glyph );
321 // Convert to bitmap if necessary
322 if ( FT_Err_Ok == error )
324 if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
326 error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
330 DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
335 DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
338 if( FT_Err_Ok == error )
340 // Access the underlying bitmap data
341 FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
342 ConvertBitmap( bitmap, bitmapGlyph->bitmap );
345 // Created FT_Glyph object must be released with FT_Done_Glyph
346 FT_Done_Glyph( glyph );
350 DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
357 void ConvertBitmap( BitmapImage& destBitmap, FT_Bitmap srcBitmap )
359 if( srcBitmap.width*srcBitmap.rows > 0 )
361 // TODO - Support all pixel modes
362 if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
364 if( srcBitmap.pitch == srcBitmap.width )
366 destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
368 PixelBuffer* destBuffer = destBitmap.GetBuffer();
369 memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
377 bool FindFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, FontId& found ) const
379 for( unsigned int i=0; i<mFontCache.size(); ++i )
381 if( mFontCache[i].mPointSize == pointSize &&
382 mFontCache[i].mPath == path &&
383 mFontCache[i].mFaceIndex == faceIndex )
393 FT_Library mFreeTypeLibrary;
395 FontList mSystemFonts;
397 std::vector<CacheItem> mFontCache;
399 unsigned int mDpiHorizontal;
400 unsigned int mDpiVertical;
403 FontClient::FontClient()
410 FontClient::~FontClient()
415 Dali::TextAbstraction::FontClient FontClient::Get()
417 Dali::TextAbstraction::FontClient fontClientHandle;
419 Dali::SingletonService service( SingletonService::Get() );
422 // Check whether the singleton is already created
423 Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
426 // If so, downcast the handle
427 FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
428 fontClientHandle = Dali::TextAbstraction::FontClient( impl );
430 else // create and register the object
432 fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
433 service.Register( typeid( fontClientHandle ), fontClientHandle );
437 return fontClientHandle;
440 void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
442 mDpiHorizontal = horizontalDpi;
443 mDpiVertical = verticalDpi;
445 // Allow DPI to be set without loading plugin
448 mPlugin->SetDpi( horizontalDpi, verticalDpi );
452 void FontClient::GetSystemFonts( FontList& systemFonts )
456 mPlugin->GetSystemFonts( systemFonts );
459 bool FontClient::FindSystemFont( Character charcode, FontDescription& systemFont )
463 return mPlugin->FindSystemFont( charcode, systemFont );
466 FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
470 return mPlugin->GetFontId( path, pointSize, faceIndex );
473 FontId FontClient::FindDefaultFont( Character charcode )
477 return mPlugin->FindDefaultFont( charcode );
480 GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
484 return mPlugin->GetGlyphIndex( fontId, charcode );
487 bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
491 return mPlugin->GetGlyphMetrics( array, size, horizontal );
494 BitmapImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
498 return mPlugin->CreateBitmap( fontId, glyphIndex );
501 void FontClient::CreatePlugin()
505 mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
506 mPlugin->Initialize();
510 } // namespace Internal
512 } // namespace FontClient