FindFont with color preference
[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                                             bool preferColor )
246 {
247   FontId fontId(0);
248   bool foundColor(false);
249
250   // Create the list of default fonts if it has not been created.
251   if( mDefaultFonts.empty() )
252   {
253     SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
254                           DEFAULT_FONT_STYLE );
255   }
256
257   // Traverse the list of default fonts.
258   // Check for each default font if supports the character.
259
260   for( FontList::const_iterator it = mDefaultFonts.begin(), endIt = mDefaultFonts.end();
261        it != endIt;
262        ++it )
263   {
264     const FontDescription& description = *it;
265
266     FcPattern* pattern = CreateFontFamilyPattern( description.family,
267                                                   description.style );
268
269     FcResult result = FcResultMatch;
270     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
271
272     FcCharSet* charSet = NULL;
273     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
274
275     if( FcCharSetHasChar( charSet, charcode ) )
276     {
277       Vector< PointSize26Dot6 > fixedSizes;
278       GetFixedSizes( description.family,
279                      description.style,
280                      fixedSizes );
281
282       const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
283       if( 0 != count )
284       {
285         // If the font is not scalable, pick the largest size <= requestedSize
286         PointSize26Dot6 size = fixedSizes[0];
287         for( unsigned int i=1; i<count; ++i )
288         {
289           if( fixedSizes[i] <= requestedSize &&
290               fixedSizes[i] > size )
291           {
292             size = fixedSizes[i];
293           }
294         }
295         requestedSize = size;
296       }
297
298       fontId = GetFontId( description.family,
299                           description.style,
300                           requestedSize,
301                           0u );
302
303       if( preferColor )
304       {
305         BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
306         if( bitmap &&
307             Pixel::BGRA8888 == bitmap.GetPixelFormat() )
308         {
309           foundColor = true;
310         }
311       }
312
313       // Keep going unless we prefer a different (color) font
314       if( !preferColor || foundColor )
315       {
316         break;
317       }
318     }
319   }
320
321   return fontId;
322 }
323
324 FontId FontClient::Plugin::GetFontId( const FontPath& path,
325                                       PointSize26Dot6 pointSize,
326                                       FaceIndex faceIndex,
327                                       bool cacheDescription )
328 {
329   FontId id( 0 );
330
331   if( NULL != mFreeTypeLibrary )
332   {
333     FontId foundId(0);
334     if( FindFont( path, pointSize, faceIndex, foundId ) )
335     {
336       id = foundId;
337     }
338     else
339     {
340       id = CreateFont( path, pointSize, faceIndex, cacheDescription );
341     }
342   }
343
344   return id;
345 }
346
347 FontId FontClient::Plugin::GetFontId( const FontFamily& fontFamily,
348                                       const FontStyle& fontStyle,
349                                       PointSize26Dot6 pointSize,
350                                       FaceIndex faceIndex )
351 {
352   // This method uses three vectors which caches:
353   // * Pairs of non validated 'fontFamily, fontStyle' and an index to a vector with paths to font file names.
354   // * The path to font file names.
355   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
356
357   // 1) Checks in the cache if the pair 'fontFamily, fontStyle' has been validated before.
358   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
359   //    retrieves using font config a path to a font file name which matches with the pair
360   //    'fontFamily, fontStyle'. The path is stored in the chache.
361   //
362   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
363   //    fon file names' exists. If exists, it gets the font id. If it doesn't it calls
364   //    the GetFontId() method with the path to the font file name and the point size to
365   //    get the font id.
366
367   // The font id to be returned.
368   FontId fontId = 0u;
369
370   // Check first if the pair font family and style have been validated before.
371   FontDescriptionId validatedFontId = 0u;
372
373   if( !FindValidatedFont( fontFamily,
374                           fontStyle,
375                           validatedFontId ) )
376   {
377     // Use font config to validate the font family name and font style.
378     ValidateFont( fontFamily, fontStyle, validatedFontId );
379   }
380
381   // Check if exists a pair 'validatedFontId, pointSize' in the cache.
382   if( !FindFont( validatedFontId, pointSize, fontId ) )
383   {
384     // Retrieve the font file name path.
385     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
386
387     // Retrieve the font id. Do not cache the description as it has been already cached.
388     fontId = GetFontId( description.path,
389                         pointSize,
390                         faceIndex,
391                         false );
392
393     // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
394     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
395                                              pointSize,
396                                              fontId ) );
397   }
398
399   return fontId;
400 }
401
402 void FontClient::Plugin::ValidateFont( const FontFamily& fontFamily,
403                                        const FontStyle& fontStyle,
404                                        FontDescriptionId& validatedFontId )
405 {
406   // Create a font pattern.
407   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
408                                                             fontStyle );
409
410   FcResult result = FcResultMatch;
411
412   // match the pattern
413   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
414
415   if( match )
416   {
417     // Get the path to the font file name.
418     FontDescription description;
419     GetFcString( match, FC_FILE, description.path );
420     GetFcString( match, FC_FAMILY, description.family );
421     GetFcString( match, FC_STYLE, description.style );
422
423     // Set the index to the vector of paths to font file names.
424     validatedFontId = mFontDescriptionCache.size();
425
426     // Add the path to the cache.
427     mFontDescriptionCache.push_back( description );
428
429     // Cache the index and the pair font family name, font style.
430     FontDescriptionCacheItem item( fontFamily, fontStyle, validatedFontId );
431     mValidatedFontCache.push_back( item );
432
433     // destroyed the matched pattern
434     FcPatternDestroy( match );
435   }
436   else
437   {
438     DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
439   }
440
441   // destroy the pattern
442   FcPatternDestroy( fontFamilyPattern );
443 }
444
445
446
447 void FontClient::Plugin::GetFontMetrics( FontId fontId,
448                                          FontMetrics& metrics )
449 {
450   if( fontId > 0 &&
451       fontId-1 < mFontCache.size() )
452   {
453     metrics = mFontCache[fontId-1].mMetrics;
454   }
455   else
456   {
457     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
458   }
459 }
460
461 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
462                                               Character charcode )
463 {
464   GlyphIndex index( 0 );
465
466   if( fontId > 0 &&
467       fontId-1 < mFontCache.size() )
468   {
469     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
470
471     index = FT_Get_Char_Index( ftFace, charcode );
472   }
473
474   return index;
475 }
476
477 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
478                                           uint32_t size,
479                                           bool horizontal )
480 {
481   bool success( true );
482
483   for( unsigned int i=0; i<size; ++i )
484   {
485     FontId fontId = array[i].fontId;
486
487     if( fontId > 0 &&
488         fontId-1 < mFontCache.size() )
489     {
490       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
491
492       // Check to see if we should be loading a Fixed Size bitmap?
493       if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
494       {
495         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
496         if ( FT_Err_Ok == error )
497         {
498           array[i].width = mFontCache[ fontId -1 ].mFixedWidthPixels;
499           array[i].height = mFontCache[ fontId -1 ].mFixedHeightPixels;
500           array[i].advance = mFontCache[ fontId -1 ].mFixedWidthPixels;
501           array[i].xBearing = 0.0f;
502           array[i].yBearing = mFontCache[ fontId -1 ].mFixedHeightPixels;
503         }
504         else
505         {
506           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
507           success = false;
508         }
509       }
510
511       int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
512
513       if( FT_Err_Ok == error )
514       {
515         array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
516         array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
517         if( horizontal )
518         {
519           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
520           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
521           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
522         }
523         else
524         {
525           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
526           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
527           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
528         }
529       }
530       else
531       {
532         success = false;
533       }
534     }
535     else
536     {
537       success = false;
538     }
539   }
540
541   return success;
542 }
543
544 BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
545                                               GlyphIndex glyphIndex )
546 {
547   BufferImage bitmap;
548
549   if( fontId > 0 &&
550       fontId-1 < mFontCache.size() )
551   {
552     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
553
554     FT_Error error;
555
556     // Check to see if this is fixed size bitmap
557     if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
558     {
559       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
560     }
561     else
562     {
563       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
564     }
565     if( FT_Err_Ok == error )
566     {
567       FT_Glyph glyph;
568       error = FT_Get_Glyph( ftFace->glyph, &glyph );
569
570       // Convert to bitmap if necessary
571       if ( FT_Err_Ok == error )
572       {
573         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
574         {
575           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
576           if ( FT_Err_Ok == error )
577           {
578             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
579             ConvertBitmap( bitmap, bitmapGlyph->bitmap );
580           }
581           else
582           {
583             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
584           }
585         }
586         else
587         {
588           ConvertBitmap( bitmap, ftFace->glyph->bitmap );
589         }
590
591         // Created FT_Glyph object must be released with FT_Done_Glyph
592         FT_Done_Glyph( glyph );
593       }
594     }
595     else
596     {
597       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
598     }
599   }
600
601   return bitmap;
602 }
603
604 void FontClient::Plugin::InitSystemFonts()
605 {
606   FcFontSet* fontSet = GetFcFontSet();
607
608   if( fontSet )
609   {
610     // Reserve some space to avoid reallocations.
611     mSystemFonts.reserve( fontSet->nfont );
612
613     for( int i = 0u; i < fontSet->nfont; ++i )
614     {
615       FcPattern* fontPattern = fontSet->fonts[i];
616
617       FontPath path;
618
619       // Skip fonts with no path
620       if( GetFcString( fontPattern, FC_FILE, path ) )
621       {
622         mSystemFonts.push_back( FontDescription() );
623         FontDescription& fontDescription = mSystemFonts.back();
624
625         fontDescription.path = path;
626
627         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
628         GetFcString( fontPattern, FC_STYLE, fontDescription.style );
629       }
630     }
631
632     FcFontSetDestroy( fontSet );
633   }
634 }
635
636 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
637                                                         const FontStyle& fontStyle )
638 {
639   // create the cached font family lookup pattern
640   // a pattern holds a set of names, each name refers to a property of the font
641   FcPattern* fontFamilyPattern = FcPatternCreate();
642
643   // add a property to the pattern for the font family
644   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
645
646   // add a property to the pattern for the font family
647   FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
648
649   // Add a property of the pattern, to say we want to match TrueType fonts
650   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
651
652   // modify the config, with the mFontFamilyPatterm
653   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
654
655   // provide default values for unspecified properties in the font pattern
656   // e.g. patterns without a specified style or weight are set to Medium
657   FcDefaultSubstitute( fontFamilyPattern );
658
659   return fontFamilyPattern;
660 }
661
662 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
663 {
664   // create a new pattern.
665   // a pattern holds a set of names, each name refers to a property of the font
666   FcPattern* pattern = FcPatternCreate();
667
668   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
669   FcObjectSet* objectSet = FcObjectSetCreate();
670
671   // build an object set from a list of property names
672   FcObjectSetAdd( objectSet, FC_FILE );
673   FcObjectSetAdd( objectSet, FC_FAMILY );
674   FcObjectSetAdd( objectSet, FC_STYLE );
675
676   // get a list of fonts
677   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
678   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
679
680   // clear up the object set
681   if( objectSet )
682   {
683     FcObjectSetDestroy( objectSet );
684   }
685   // clear up the pattern
686   if( pattern )
687   {
688     FcPatternDestroy( pattern );
689   }
690
691   return fontset;
692 }
693
694 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
695                                       const char* const n,
696                                       std::string& string )
697 {
698   FcChar8* file = NULL;
699   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
700
701   if( FcResultMatch == retVal )
702   {
703     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
704     string.assign( reinterpret_cast<const char*>( file ) );
705
706     return true;
707   }
708
709   return false;
710 }
711
712 FontId FontClient::Plugin::CreateFont( const FontPath& path,
713                                        PointSize26Dot6 pointSize,
714                                        FaceIndex faceIndex,
715                                        bool cacheDescription )
716 {
717   FontId id( 0 );
718
719   // Create & cache new font face
720   FT_Face ftFace;
721   int error = FT_New_Face( mFreeTypeLibrary,
722                            path.c_str(),
723                            0,
724                            &ftFace );
725
726   if( FT_Err_Ok == error )
727   {
728     // Check to see if the font contains fixed sizes?
729     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
730     {
731       // Ensure this size is available
732       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
733       {
734         if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
735         {
736           // Tell Freetype to use this size
737           error = FT_Select_Size( ftFace, i );
738           if ( FT_Err_Ok != error )
739           {
740             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
741           }
742           else
743           {
744             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
745             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
746
747             // Indicate that the font is a fixed sized bitmap
748             FontMetrics metrics( 0.0f,
749                                  0.0f,
750                                  fixedHeight );
751
752             mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
753             id = mFontCache.size();
754
755             if( cacheDescription )
756             {
757               FontDescription description;
758               description.path = path;
759               description.family = FontFamily( ftFace->family_name );
760               description.style = FontStyle( ftFace->style_name );
761
762               mFontDescriptionCache.push_back( description );
763             }
764             return id;
765           }
766         }
767       }
768
769       // Can't find this size
770       std::stringstream sizes;
771       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
772       {
773         if ( i )
774         {
775           sizes << ", ";
776         }
777         sizes << ftFace->available_sizes[ i ].size;
778       }
779       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
780                        path.c_str(), pointSize, sizes.str().c_str() );
781     }
782     else
783     {
784       error = FT_Set_Char_Size( ftFace,
785                               0,
786                               pointSize,
787                               mDpiHorizontal,
788                               mDpiVertical );
789
790       if( FT_Err_Ok == error )
791       {
792
793         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
794
795         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
796                              static_cast< float >( ftMetrics.descender ) * FROM_266,
797                              static_cast< float >( ftMetrics.height    ) * FROM_266 );
798
799         mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
800         id = mFontCache.size();
801
802         if( cacheDescription )
803         {
804           FontDescription description;
805           description.path = path;
806           description.family = FontFamily( ftFace->family_name );
807           description.style = FontStyle( ftFace->style_name );
808
809           mFontDescriptionCache.push_back( description );
810         }
811       }
812       else
813       {
814         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
815       }
816     }
817   }
818   else
819   {
820     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
821   }
822
823   return id;
824 }
825
826 void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
827                                         FT_Bitmap srcBitmap )
828 {
829   if( srcBitmap.width*srcBitmap.rows > 0 )
830   {
831     switch( srcBitmap.pixel_mode )
832     {
833       case FT_PIXEL_MODE_GRAY:
834       {
835         if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
836         {
837           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
838
839           PixelBuffer* destBuffer = destBitmap.GetBuffer();
840           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
841         }
842         break;
843       }
844
845       case FT_PIXEL_MODE_BGRA:
846       {
847         if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
848         {
849           destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
850
851           PixelBuffer* destBuffer = destBitmap.GetBuffer();
852           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
853         }
854         break;
855       }
856       default:
857       {
858         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
859         break;
860       }
861     }
862   }
863 }
864
865 bool FontClient::Plugin::FindFont( const FontPath& path,
866                                    PointSize26Dot6 pointSize,
867                                    FaceIndex faceIndex,
868                                    FontId& fontId ) const
869 {
870   fontId = 0u;
871   for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
872          endIt = mFontCache.end();
873        it != endIt;
874        ++it, ++fontId )
875   {
876     const CacheItem& cacheItem = *it;
877
878     if( cacheItem.mPointSize == pointSize &&
879         cacheItem.mFaceIndex == faceIndex &&
880         cacheItem.mPath == path )
881     {
882       ++fontId;
883       return true;
884     }
885   }
886
887   return false;
888 }
889
890 bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
891                                             const FontStyle& fontStyle,
892                                             FontDescriptionId& validatedFontId )
893 {
894   validatedFontId = 0u;
895
896   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
897          endIt = mValidatedFontCache.end();
898        it != endIt;
899        ++it )
900   {
901     const FontDescriptionCacheItem& item = *it;
902
903     if( ( fontFamily == item.fontFamily ) &&
904         ( fontStyle == item.fontStyle ) )
905     {
906       validatedFontId = item.index;
907
908       return true;
909     }
910   }
911
912   return false;
913 }
914
915 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
916                                    PointSize26Dot6 pointSize,
917                                    FontId& fontId )
918 {
919   fontId = 0u;
920
921   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
922          endIt = mFontIdCache.end();
923        it != endIt;
924        ++it )
925   {
926     const FontIdCacheItem& item = *it;
927
928     if( ( validatedFontId == item.validatedFontId ) &&
929         ( pointSize == item.pointSize ) )
930     {
931       fontId = item.fontId;
932       return true;
933     }
934   }
935
936   return false;
937 }
938
939 bool FontClient::Plugin::IsScalable( const FontPath& path )
940 {
941   FT_Face ftFace;
942   int error = FT_New_Face( mFreeTypeLibrary,
943                            path.c_str(),
944                            0,
945                            &ftFace );
946   if( FT_Err_Ok != error )
947   {
948     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
949   }
950   return ( ftFace->num_fixed_sizes == 0 );
951 }
952
953 bool FontClient::Plugin::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
954 {
955   // Create a font pattern.
956   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
957                                                           fontStyle );
958
959   FcResult result = FcResultMatch;
960
961   // match the pattern
962   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
963
964   if( match )
965   {
966     // Get the path to the font file name.
967     FontPath path;
968     GetFcString( match, FC_FILE, path );
969     return IsScalable( path );
970   }
971   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
972   return true;
973 }
974
975 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
976 {
977   // Empty the caller container
978   sizes.Clear();
979
980   FT_Face ftFace;
981   int error = FT_New_Face( mFreeTypeLibrary,
982                            path.c_str(),
983                            0,
984                            &ftFace );
985   if( FT_Err_Ok != error )
986   {
987     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
988   }
989
990   // Fetch the number of fixed sizes available
991   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
992   {
993     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
994     {
995       sizes.PushBack( ftFace->available_sizes[ i ].size );
996     }
997   }
998 }
999
1000 void FontClient::Plugin::GetFixedSizes( const FontFamily& fontFamily,
1001                                         const FontStyle& fontStyle,
1002                                         Vector< PointSize26Dot6 >& sizes )
1003 {
1004   // Create a font pattern.
1005   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
1006                                                           fontStyle );
1007
1008   FcResult result = FcResultMatch;
1009
1010   // match the pattern
1011   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1012
1013   if( match )
1014   {
1015     // Get the path to the font file name.
1016     FontPath path;
1017     GetFcString( match, FC_FILE, path );
1018     return GetFixedSizes( path, sizes );
1019   }
1020   DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
1021 }
1022
1023 } // namespace Internal
1024
1025 } // namespace TextAbstraction
1026
1027 } // namespace Dali