Fix GlyphMetrics for fixed-size fonts
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / font-client-plugin-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/text-abstraction/font-client-plugin-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/dali-vector.h>
23 #include <dali/public-api/common/vector-wrapper.h>
24 #include <dali/public-api/text-abstraction/glyph-info.h>
25 #include <dali/integration-api/debug.h>
26
27 // EXTERNAL INCLUDES
28 #include <fontconfig/fontconfig.h>
29
30 /**
31  * Conversion from Fractional26.6 to float
32  */
33 namespace
34 {
35 const float FROM_266 = 1.0f / 64.0f;
36
37 const std::string FONT_FORMAT( "TrueType" );
38 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
39 const std::string DEFAULT_FONT_STYLE( "Regular" );
40 }
41
42 using Dali::Vector;
43
44 namespace Dali
45 {
46
47 namespace TextAbstraction
48 {
49
50 namespace Internal
51 {
52
53 const bool FONT_FIXED_SIZE_BITMAP( true );
54
55 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontFamily& fontFamily,
56                                                                         const FontStyle& fontStyle,
57                                                                         FontDescriptionId index )
58 : fontFamily( fontFamily ),
59   fontStyle( fontStyle ),
60   index( index )
61 {
62 }
63
64 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
65                                                       PointSize26Dot6 pointSize,
66                                                       FontId fontId )
67 : validatedFontId( validatedFontId ),
68   pointSize( pointSize ),
69   fontId( fontId )
70 {
71 }
72
73 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
74                                           const FontPath& path,
75                                           PointSize26Dot6 pointSize,
76                                           FaceIndex face,
77                                           const FontMetrics& metrics )
78 : mFreeTypeFace( ftFace ),
79   mPath( path ),
80   mPointSize( pointSize ),
81   mFaceIndex( face ),
82   mMetrics( metrics ),
83   mFixedWidthPixels( 0.0f ),
84   mFixedHeightPixels( 0.0f ),
85   mIsFixedSizeBitmap( false )
86 {
87 }
88
89 FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
90                                           const FontPath& path,
91                                           PointSize26Dot6 pointSize,
92                                           FaceIndex face,
93                                           const FontMetrics& metrics,
94                                           float fixedWidth,
95                                           float fixedHeight )
96 : mFreeTypeFace( ftFace ),
97   mPath( path ),
98   mPointSize( pointSize ),
99   mFaceIndex( face ),
100   mMetrics( metrics ),
101   mFixedWidthPixels( fixedWidth ),
102   mFixedHeightPixels( fixedHeight ),
103   mIsFixedSizeBitmap( true )
104 {
105 }
106
107 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
108                             unsigned int verticalDpi )
109 : mFreeTypeLibrary( NULL ),
110   mDpiHorizontal( horizontalDpi ),
111   mDpiVertical( verticalDpi ),
112   mSystemFonts(),
113   mDefaultFonts(),
114   mFontCache(),
115   mValidatedFontCache(),
116   mFontDescriptionCache( 1u ),
117   mFontIdCache()
118 {
119   int error = FT_Init_FreeType( &mFreeTypeLibrary );
120   if( FT_Err_Ok != error )
121   {
122     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
123   }
124 }
125
126 FontClient::Plugin::~Plugin()
127 {
128   FT_Done_FreeType( mFreeTypeLibrary );
129 }
130
131 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
132                                  unsigned int verticalDpi )
133 {
134   mDpiHorizontal = horizontalDpi;
135   mDpiVertical = verticalDpi;
136 }
137
138 void FontClient::Plugin::SetDefaultFontFamily( const FontFamily& fontFamilyName,
139                                                const FontStyle& fontStyle )
140 {
141   mDefaultFonts.clear();
142
143   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamilyName,
144                                                           fontStyle );
145
146   FcResult result = FcResultMatch;
147
148   // Match the pattern.
149   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
150                                    fontFamilyPattern,
151                                    false /* don't trim */,
152                                    NULL,
153                                    &result );
154
155   if( NULL != fontSet )
156   {
157     // Reserve some space to avoid reallocations.
158     mDefaultFonts.reserve( fontSet->nfont );
159
160     for( int i = 0u; i < fontSet->nfont; ++i )
161     {
162       FcPattern* fontPattern = fontSet->fonts[i];
163
164       FontPath path;
165
166       // Skip fonts with no path
167       if( GetFcString( fontPattern, FC_FILE, path ) )
168       {
169         mDefaultFonts.push_back( FontDescription() );
170         FontDescription& fontDescription = mDefaultFonts.back();
171
172         fontDescription.path = path;
173
174         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
175         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
176       }
177     }
178
179     FcFontSetDestroy( fontSet );
180   }
181
182   FcPatternDestroy( fontFamilyPattern );
183 }
184
185 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
186 {
187   if( mDefaultFonts.empty() )
188   {
189     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
190                           DEFAULT_FONT_STYLE );
191   }
192
193   defaultFonts = mDefaultFonts;
194 }
195
196 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
197 {
198   if( mSystemFonts.empty() )
199   {
200     InitSystemFonts();
201   }
202
203   systemFonts = mSystemFonts;
204 }
205
206 void FontClient::Plugin::GetDescription( FontId id,
207                                          FontDescription& fontDescription ) const
208 {
209   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
210          endIt = mFontIdCache.end();
211        it != endIt;
212        ++it )
213   {
214     const FontIdCacheItem& item = *it;
215
216     if( item.fontId == id )
217     {
218       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
219       return;
220     }
221   }
222
223   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
224 }
225
226 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
227 {
228   const FontId index = id - 1u;
229
230   if( id > 0u &&
231       index < mFontCache.size() )
232   {
233     return ( *( mFontCache.begin() + index ) ).mPointSize;
234   }
235   else
236   {
237     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
238   }
239
240   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
241 }
242
243 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
244                                             PointSize26Dot6 requestedSize )
245 {
246   // Create the list of default fonts if it has not been created.
247   if( mDefaultFonts.empty() )
248   {
249     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
250                           DEFAULT_FONT_STYLE );
251   }
252
253   // Traverse the list of default fonts.
254   // Check for each default font if supports the character.
255
256   for( FontList::const_iterator it = mDefaultFonts.begin(),
257          endIt = mDefaultFonts.end();
258        it != endIt;
259        ++it )
260   {
261     const FontDescription& description = *it;
262
263     FcPattern* pattern = CreateFontFamilyPattern( description.family,
264                                                   description.style );
265
266     FcResult result = FcResultMatch;
267     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
268
269     FcCharSet* charSet = NULL;
270     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
271
272     if( FcCharSetHasChar( charSet, charcode ) )
273     {
274       Vector< PointSize26Dot6 > fixedSizes;
275       GetFixedSizes( description.family,
276                      description.style,
277                      fixedSizes );
278
279       const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
280       if( 0 != count )
281       {
282         // If the font is not scalable, pick the largest size <= requestedSize
283         PointSize26Dot6 size = fixedSizes[0];
284         for( unsigned int i=1; i<count; ++i )
285         {
286           if( fixedSizes[i] <= requestedSize &&
287               fixedSizes[i] > size )
288           {
289             size = fixedSizes[i];
290           }
291         }
292         requestedSize = size;
293       }
294
295       return GetFontId( description.family,
296                         description.style,
297                         requestedSize,
298                         0u );
299     }
300   }
301
302   return 0u;
303 }
304
305 FontId FontClient::Plugin::GetFontId( const FontPath& path,
306                                       PointSize26Dot6 pointSize,
307                                       FaceIndex faceIndex,
308                                       bool cacheDescription )
309 {
310   FontId id( 0 );
311
312   if( NULL != mFreeTypeLibrary )
313   {
314     FontId foundId(0);
315     if( FindFont( path, pointSize, faceIndex, foundId ) )
316     {
317       id = foundId;
318     }
319     else
320     {
321       id = CreateFont( path, pointSize, faceIndex, cacheDescription );
322     }
323   }
324
325   return id;
326 }
327
328 FontId FontClient::Plugin::GetFontId( const FontFamily& fontFamily,
329                                       const FontStyle& fontStyle,
330                                       PointSize26Dot6 pointSize,
331                                       FaceIndex faceIndex )
332 {
333   // This method uses three vectors which caches:
334   // * Pairs of non validated 'fontFamily, fontStyle' and an index to a vector with paths to font file names.
335   // * The path to font file names.
336   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
337
338   // 1) Checks in the cache if the pair 'fontFamily, fontStyle' has been validated before.
339   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
340   //    retrieves using font config a path to a font file name which matches with the pair
341   //    'fontFamily, fontStyle'. The path is stored in the chache.
342   //
343   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
344   //    fon file names' exists. If exists, it gets the font id. If it doesn't it calls
345   //    the GetFontId() method with the path to the font file name and the point size to
346   //    get the font id.
347
348   // The font id to be returned.
349   FontId fontId = 0u;
350
351   // Check first if the pair font family and style have been validated before.
352   FontDescriptionId validatedFontId = 0u;
353
354   if( !FindValidatedFont( fontFamily,
355                           fontStyle,
356                           validatedFontId ) )
357   {
358     // Use font config to validate the font family name and font style.
359     ValidateFont( fontFamily, fontStyle, validatedFontId );
360   }
361
362   // Check if exists a pair 'validatedFontId, pointSize' in the cache.
363   if( !FindFont( validatedFontId, pointSize, fontId ) )
364   {
365     // Retrieve the font file name path.
366     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
367
368     // Retrieve the font id. Do not cache the description as it has been already cached.
369     fontId = GetFontId( description.path,
370                         pointSize,
371                         faceIndex,
372                         false );
373
374     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
375     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
376                                              pointSize,
377                                              fontId ) );
378   }
379
380   return fontId;
381 }
382
383 void FontClient::Plugin::ValidateFont( const FontFamily& fontFamily,
384                                        const FontStyle& fontStyle,
385                                        FontDescriptionId& validatedFontId )
386 {
387   // Create a font pattern.
388   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
389                                                             fontStyle );
390
391   FcResult result = FcResultMatch;
392
393   // match the pattern
394   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
395
396   if( match )
397   {
398     // Get the path to the font file name.
399     FontDescription description;
400     GetFcString( match, FC_FILE, description.path );
401     GetFcString( match, FC_FAMILY, description.family );
402     GetFcString( match, FC_STYLE, description.style );
403
404     // Set the index to the vector of paths to font file names.
405     validatedFontId = mFontDescriptionCache.size();
406
407     // Add the path to the cache.
408     mFontDescriptionCache.push_back( description );
409
410     // Cache the index and the pair font family name, font style.
411     FontDescriptionCacheItem item( fontFamily, fontStyle, validatedFontId );
412     mValidatedFontCache.push_back( item );
413
414     // destroyed the matched pattern
415     FcPatternDestroy( match );
416   }
417   else
418   {
419     DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
420   }
421
422   // destroy the pattern
423   FcPatternDestroy( fontFamilyPattern );
424 }
425
426
427
428 void FontClient::Plugin::GetFontMetrics( FontId fontId,
429                                          FontMetrics& metrics )
430 {
431   if( fontId > 0 &&
432       fontId-1 < mFontCache.size() )
433   {
434     metrics = mFontCache[fontId-1].mMetrics;
435   }
436   else
437   {
438     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
439   }
440 }
441
442 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
443                                               Character charcode )
444 {
445   GlyphIndex index( 0 );
446
447   if( fontId > 0 &&
448       fontId-1 < mFontCache.size() )
449   {
450     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
451
452     index = FT_Get_Char_Index( ftFace, charcode );
453   }
454
455   return index;
456 }
457
458 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
459                                           uint32_t size,
460                                           bool horizontal )
461 {
462   bool success( true );
463
464   for( unsigned int i=0; i<size; ++i )
465   {
466     FontId fontId = array[i].fontId;
467
468     if( fontId > 0 &&
469         fontId-1 < mFontCache.size() )
470     {
471       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
472
473       // Check to see if we should be loading a Fixed Size bitmap?
474       if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
475       {
476         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
477         if ( FT_Err_Ok == error )
478         {
479           array[i].width = mFontCache[ fontId -1 ].mFixedWidthPixels;
480           array[i].height = mFontCache[ fontId -1 ].mFixedHeightPixels;
481           array[i].advance = mFontCache[ fontId -1 ].mFixedWidthPixels;
482           array[i].xBearing = 0.0f;
483           array[i].yBearing = mFontCache[ fontId -1 ].mFixedHeightPixels;
484         }
485         else
486         {
487           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
488           success = false;
489         }
490       }
491
492       int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
493
494       if( FT_Err_Ok == error )
495       {
496         array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
497         array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
498         if( horizontal )
499         {
500           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
501           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
502           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
503         }
504         else
505         {
506           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
507           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
508           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
509         }
510       }
511       else
512       {
513         success = false;
514       }
515     }
516     else
517     {
518       success = false;
519     }
520   }
521
522   return success;
523 }
524
525 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
526                                               GlyphIndex glyphIndex )
527 {
528   BufferImage bitmap;
529
530   if( fontId > 0 &&
531       fontId-1 < mFontCache.size() )
532   {
533     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
534
535     FT_Error error;
536
537     // Check to see if this is fixed size bitmap
538     if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
539     {
540       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
541     }
542     else
543     {
544       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
545     }
546     if( FT_Err_Ok == error )
547     {
548       FT_Glyph glyph;
549       error = FT_Get_Glyph( ftFace->glyph, &glyph );
550
551       // Convert to bitmap if necessary
552       if ( FT_Err_Ok == error )
553       {
554         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
555         {
556           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
557           if ( FT_Err_Ok == error )
558           {
559             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
560             ConvertBitmap( bitmap, bitmapGlyph->bitmap );
561           }
562           else
563           {
564             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
565           }
566         }
567         else
568         {
569           ConvertBitmap( bitmap, ftFace->glyph->bitmap );
570         }
571
572         // Created FT_Glyph object must be released with FT_Done_Glyph
573         FT_Done_Glyph( glyph );
574       }
575     }
576     else
577     {
578       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
579     }
580   }
581
582   return bitmap;
583 }
584
585 void FontClient::Plugin::InitSystemFonts()
586 {
587   FcFontSet* fontSet = GetFcFontSet();
588
589   if( fontSet )
590   {
591     // Reserve some space to avoid reallocations.
592     mSystemFonts.reserve( fontSet->nfont );
593
594     for( int i = 0u; i < fontSet->nfont; ++i )
595     {
596       FcPattern* fontPattern = fontSet->fonts[i];
597
598       FontPath path;
599
600       // Skip fonts with no path
601       if( GetFcString( fontPattern, FC_FILE, path ) )
602       {
603         mSystemFonts.push_back( FontDescription() );
604         FontDescription& fontDescription = mSystemFonts.back();
605
606         fontDescription.path = path;
607
608         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
609         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
610       }
611     }
612
613     FcFontSetDestroy( fontSet );
614   }
615 }
616
617 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
618                                                         const FontStyle& fontStyle )
619 {
620   // create the cached font family lookup pattern
621   // a pattern holds a set of names, each name refers to a property of the font
622   FcPattern* fontFamilyPattern = FcPatternCreate();
623
624   // add a property to the pattern for the font family
625   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
626
627   // add a property to the pattern for the font family
628   FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
629
630   // Add a property of the pattern, to say we want to match TrueType fonts
631   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
632
633   // modify the config, with the mFontFamilyPatterm
634   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
635
636   // provide default values for unspecified properties in the font pattern
637   // e.g. patterns without a specified style or weight are set to Medium
638   FcDefaultSubstitute( fontFamilyPattern );
639
640   return fontFamilyPattern;
641 }
642
643 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
644 {
645   // create a new pattern.
646   // a pattern holds a set of names, each name refers to a property of the font
647   FcPattern* pattern = FcPatternCreate();
648
649   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
650   FcObjectSet* objectSet = FcObjectSetCreate();
651
652   // build an object set from a list of property names
653   FcObjectSetAdd( objectSet, FC_FILE );
654   FcObjectSetAdd( objectSet, FC_FAMILY );
655   FcObjectSetAdd( objectSet, FC_STYLE );
656
657   // get a list of fonts
658   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
659   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
660
661   // clear up the object set
662   if( objectSet )
663   {
664     FcObjectSetDestroy( objectSet );
665   }
666   // clear up the pattern
667   if( pattern )
668   {
669     FcPatternDestroy( pattern );
670   }
671
672   return fontset;
673 }
674
675 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
676                                       const char* const n,
677                                       std::string& string )
678 {
679   FcChar8* file = NULL;
680   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
681
682   if( FcResultMatch == retVal )
683   {
684     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
685     string.assign( reinterpret_cast<const char*>( file ) );
686
687     return true;
688   }
689
690   return false;
691 }
692
693 FontId FontClient::Plugin::CreateFont( const FontPath& path,
694                                        PointSize26Dot6 pointSize,
695                                        FaceIndex faceIndex,
696                                        bool cacheDescription )
697 {
698   FontId id( 0 );
699
700   // Create & cache new font face
701   FT_Face ftFace;
702   int error = FT_New_Face( mFreeTypeLibrary,
703                            path.c_str(),
704                            0,
705                            &ftFace );
706
707   if( FT_Err_Ok == error )
708   {
709     // Check to see if the font contains fixed sizes?
710     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
711     {
712       // Ensure this size is available
713       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
714       {
715         if ( pointSize == ftFace->available_sizes[ i ].size )
716         {
717           // Tell Freetype to use this size
718           error = FT_Select_Size( ftFace, i );
719           if ( FT_Err_Ok != error )
720           {
721             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
722           }
723           else
724           {
725             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
726             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
727
728             // Indicate that the font is a fixed sized bitmap
729             FontMetrics metrics( 0.0f,
730                                  0.0f,
731                                  fixedHeight );
732
733             mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
734             id = mFontCache.size();
735
736             if( cacheDescription )
737             {
738               FontDescription description;
739               description.path = path;
740               description.family = FontFamily( ftFace->family_name );
741               description.style = FontStyle( ftFace->style_name );
742
743               mFontDescriptionCache.push_back( description );
744             }
745             return id;
746           }
747         }
748       }
749
750       // Can't find this size
751       std::stringstream sizes;
752       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
753       {
754         if ( i )
755         {
756           sizes << ", ";
757         }
758         sizes << ftFace->available_sizes[ i ].size;
759       }
760       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
761                        path.c_str(), pointSize, sizes.str().c_str() );
762     }
763     else
764     {
765       error = FT_Set_Char_Size( ftFace,
766                               0,
767                               pointSize,
768                               mDpiHorizontal,
769                               mDpiVertical );
770
771       if( FT_Err_Ok == error )
772       {
773
774         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
775
776         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
777                              static_cast< float >( ftMetrics.descender ) * FROM_266,
778                              static_cast< float >( ftMetrics.height    ) * FROM_266 );
779
780         mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
781         id = mFontCache.size();
782
783         if( cacheDescription )
784         {
785           FontDescription description;
786           description.path = path;
787           description.family = FontFamily( ftFace->family_name );
788           description.style = FontStyle( ftFace->style_name );
789
790           mFontDescriptionCache.push_back( description );
791         }
792       }
793       else
794       {
795         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
796       }
797     }
798   }
799   else
800   {
801     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
802   }
803
804   return id;
805 }
806
807 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
808                                         FT_Bitmap srcBitmap )
809 {
810   if( srcBitmap.width*srcBitmap.rows > 0 )
811   {
812     switch( srcBitmap.pixel_mode )
813     {
814       case FT_PIXEL_MODE_GRAY:
815       {
816         if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
817         {
818           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
819
820           PixelBuffer* destBuffer = destBitmap.GetBuffer();
821           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
822         }
823         break;
824       }
825
826       case FT_PIXEL_MODE_BGRA:
827       {
828         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
829         {
830           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
831
832           PixelBuffer* destBuffer = destBitmap.GetBuffer();
833           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
834         }
835         break;
836       }
837       default:
838       {
839         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
840         break;
841       }
842     }
843   }
844 }
845
846 bool FontClient::Plugin::FindFont( const FontPath& path,
847                                    PointSize26Dot6 pointSize,
848                                    FaceIndex faceIndex,
849                                    FontId& fontId ) const
850 {
851   fontId = 0u;
852   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
853          endIt = mFontCache.end();
854        it != endIt;
855        ++it, ++fontId )
856   {
857     const CacheItem& cacheItem = *it;
858
859     if( cacheItem.mPointSize == pointSize &&
860         cacheItem.mFaceIndex == faceIndex &&
861         cacheItem.mPath == path )
862     {
863       ++fontId;
864       return true;
865     }
866   }
867
868   return false;
869 }
870
871 bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
872                                             const FontStyle& fontStyle,
873                                             FontDescriptionId& validatedFontId )
874 {
875   validatedFontId = 0u;
876
877   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
878          endIt = mValidatedFontCache.end();
879        it != endIt;
880        ++it )
881   {
882     const FontDescriptionCacheItem& item = *it;
883
884     if( ( fontFamily == item.fontFamily ) &&
885         ( fontStyle == item.fontStyle ) )
886     {
887       validatedFontId = item.index;
888
889       return true;
890     }
891   }
892
893   return false;
894 }
895
896 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
897                                    PointSize26Dot6 pointSize,
898                                    FontId& fontId )
899 {
900   fontId = 0u;
901
902   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
903          endIt = mFontIdCache.end();
904        it != endIt;
905        ++it )
906   {
907     const FontIdCacheItem& item = *it;
908
909     if( ( validatedFontId == item.validatedFontId ) &&
910         ( pointSize == item.pointSize ) )
911     {
912       fontId = item.fontId;
913       return true;
914     }
915   }
916
917   return false;
918 }
919
920 bool FontClient::Plugin::IsScalable( const FontPath& path )
921 {
922   FT_Face ftFace;
923   int error = FT_New_Face( mFreeTypeLibrary,
924                            path.c_str(),
925                            0,
926                            &ftFace );
927   if( FT_Err_Ok != error )
928   {
929     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
930   }
931   return ( ftFace->num_fixed_sizes == 0 );
932 }
933
934 bool FontClient::Plugin::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
935 {
936   // Create a font pattern.
937   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
938                                                           fontStyle );
939
940   FcResult result = FcResultMatch;
941
942   // match the pattern
943   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
944
945   if( match )
946   {
947     // Get the path to the font file name.
948     FontPath path;
949     GetFcString( match, FC_FILE, path );
950     return IsScalable( path );
951   }
952   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
953   return true;
954 }
955
956 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
957 {
958   // Empty the caller container
959   sizes.Clear();
960
961   FT_Face ftFace;
962   int error = FT_New_Face( mFreeTypeLibrary,
963                            path.c_str(),
964                            0,
965                            &ftFace );
966   if( FT_Err_Ok != error )
967   {
968     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
969   }
970
971   // Fetch the number of fixed sizes available
972   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
973   {
974     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
975     {
976       sizes.PushBack( ftFace->available_sizes[ i ].size );
977     }
978   }
979 }
980
981 void FontClient::Plugin::GetFixedSizes( const FontFamily& fontFamily,
982                                         const FontStyle& fontStyle,
983                                         Vector< PointSize26Dot6 >& sizes )
984 {
985   // Create a font pattern.
986   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
987                                                           fontStyle );
988
989   FcResult result = FcResultMatch;
990
991   // match the pattern
992   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
993
994   if( match )
995   {
996     // Get the path to the font file name.
997     FontPath path;
998     GetFcString( match, FC_FILE, path );
999     return GetFixedSizes( path, sizes );
1000   }
1001   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
1002 }
1003
1004 } // namespace Internal
1005
1006 } // namespace TextAbstraction
1007
1008 } // namespace Dali