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