970f0ffe8edd2d4a35e8f3f0fcaebb1e7e3afea8
[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/devel-api/text-abstraction/font-list.h>
23 #include <dali/public-api/common/dali-vector.h>
24 #include <dali/public-api/common/vector-wrapper.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/internal/text-abstraction/font-client-helper.h>
28 #include <platform-abstractions/portable/image-operations.h>
29 #include <adaptor-impl.h>
30
31 // EXTERNAL INCLUDES
32 #include <fontconfig/fontconfig.h>
33
34 namespace
35 {
36
37 #if defined(DEBUG_ENABLED)
38 Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
39 #endif
40
41 /**
42  * Conversion from Fractional26.6 to float
43  */
44 const float FROM_266 = 1.0f / 64.0f;
45 const float POINTS_PER_INCH = 72.f;
46
47 const std::string FONT_FORMAT( "TrueType" );
48 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
49 const int DEFAULT_FONT_WIDTH  = 100; // normal
50 const int DEFAULT_FONT_WEIGHT =  80; // normal
51 const int DEFAULT_FONT_SLANT  =   0; // normal
52
53 const uint32_t ELLIPSIS_CHARACTER = 0x2026;
54
55 const bool FONT_FIXED_SIZE_BITMAP( true );
56
57 // http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
58
59 // NONE            -1  --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
60 // ULTRA_CONDENSED 50
61 // EXTRA_CONDENSED 63
62 // CONDENSED       75
63 // SEMI_CONDENSED  87
64 // NORMAL         100
65 // SEMI_EXPANDED  113
66 // EXPANDED       125
67 // EXTRA_EXPANDED 150
68 // ULTRA_EXPANDED 200
69 const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
70 const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
71
72 // NONE                       -1  --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
73 // THIN                        0
74 // ULTRA_LIGHT, EXTRA_LIGHT   40
75 // LIGHT                      50
76 // DEMI_LIGHT, SEMI_LIGHT     55
77 // BOOK                       75
78 // NORMAL, REGULAR            80
79 // MEDIUM                    100
80 // DEMI_BOLD, SEMI_BOLD      180
81 // BOLD                      200
82 // ULTRA_BOLD, EXTRA_BOLD    205
83 // BLACK, HEAVY, EXTRA_BLACK 210
84 const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
85 const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
86
87 // NONE             -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
88 // NORMAL, ROMAN     0
89 // ITALIC          100
90 // OBLIQUE         110
91 const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
92 const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
93
94 } // namespace
95
96 using Dali::Vector;
97
98 namespace Dali
99 {
100
101 namespace TextAbstraction
102 {
103
104 namespace Internal
105 {
106
107 /**
108  * @brief Returns the FontWidth's enum index for the given width value.
109  *
110  * @param[in] width The width value.
111  *
112  * @return The FontWidth's enum index.
113  */
114 FontWidth::Type IntToWidthType( int width )
115 {
116   return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
117 }
118
119 /**
120  * @brief Returns the FontWeight's enum index for the given weight value.
121  *
122  * @param[in] weight The weight value.
123  *
124  * @return The FontWeight's enum index.
125  */
126 FontWeight::Type IntToWeightType( int weight )
127 {
128   return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
129 }
130
131 /**
132  * @brief Returns the FontSlant's enum index for the given slant value.
133  *
134  * @param[in] slant The slant value.
135  *
136  * @return The FontSlant's enum index.
137  */
138 FontSlant::Type IntToSlantType( int slant )
139 {
140   return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
141 }
142
143 FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list )
144 : fontDescription( font ),
145   fallbackFonts( list )
146 {
147 }
148
149 FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
150                                                                         FontDescriptionId index )
151 : fontDescription( fontDescription ),
152   index( index )
153 {
154 }
155
156 FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
157                                                       PointSize26Dot6 requestedPointSize,
158                                                       FontId fontId )
159 : validatedFontId( validatedFontId ),
160   requestedPointSize( requestedPointSize ),
161   fontId( fontId )
162 {
163 }
164
165 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
166                                                           const FontPath& path,
167                                                           PointSize26Dot6 requestedPointSize,
168                                                           FaceIndex face,
169                                                           const FontMetrics& metrics )
170 : mFreeTypeFace( ftFace ),
171   mPath( path ),
172   mRequestedPointSize( requestedPointSize ),
173   mFaceIndex( face ),
174   mMetrics( metrics ),
175   mFixedWidthPixels( 0.0f ),
176   mFixedHeightPixels( 0.0f ),
177   mVectorFontId( 0 ),
178   mIsFixedSizeBitmap( false )
179 {
180 }
181
182 FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
183                                                           const FontPath& path,
184                                                           PointSize26Dot6 requestedPointSize,
185                                                           FaceIndex face,
186                                                           const FontMetrics& metrics,
187                                                           float fixedWidth,
188                                                           float fixedHeight )
189 : mFreeTypeFace( ftFace ),
190   mPath( path ),
191   mRequestedPointSize( requestedPointSize ),
192   mFaceIndex( face ),
193   mMetrics( metrics ),
194   mFixedWidthPixels( fixedWidth ),
195   mFixedHeightPixels( fixedHeight ),
196   mVectorFontId( 0 ),
197   mIsFixedSizeBitmap( true )
198 {
199 }
200
201 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
202                             unsigned int verticalDpi )
203 : mFreeTypeLibrary( NULL ),
204   mDpiHorizontal( horizontalDpi ),
205   mDpiVertical( verticalDpi ),
206   mDefaultFontDescription(),
207   mSystemFonts(),
208   mDefaultFonts(),
209   mFontCache(),
210   mValidatedFontCache(),
211   mFontDescriptionCache( 1u ),
212   mFontIdCache(),
213   mVectorFontCache( NULL ),
214   mEllipsisCache(),
215   mDefaultFontDescriptionCached( false )
216 {
217   int error = FT_Init_FreeType( &mFreeTypeLibrary );
218   if( FT_Err_Ok != error )
219   {
220     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
221   }
222
223 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
224   mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
225 #endif
226 }
227
228 FontClient::Plugin::~Plugin()
229 {
230   for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
231        it != endIt;
232        ++it )
233   {
234     FallbackCacheItem& item = *it;
235
236     if( item.fallbackFonts )
237     {
238       delete item.fallbackFonts;
239       item.fallbackFonts = NULL;
240     }
241   }
242
243 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
244   delete mVectorFontCache;
245 #endif
246
247   FT_Done_FreeType( mFreeTypeLibrary );
248 }
249
250 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
251                                  unsigned int verticalDpi )
252 {
253   mDpiHorizontal = horizontalDpi;
254   mDpiVertical = verticalDpi;
255 }
256
257 void FontClient::Plugin::ResetSystemDefaults()
258 {
259   mDefaultFontDescriptionCached = false;
260 }
261
262 void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList )
263 {
264   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() );
265
266   fontList.clear();
267
268   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
269
270   FcResult result = FcResultMatch;
271
272   // Match the pattern.
273   FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
274                                    fontFamilyPattern,
275                                    false /* don't trim */,
276                                    NULL,
277                                    &result );
278
279   if( NULL != fontSet )
280   {
281     // Reserve some space to avoid reallocations.
282     fontList.reserve( fontSet->nfont );
283
284     for( int i = 0u; i < fontSet->nfont; ++i )
285     {
286       FcPattern* fontPattern = fontSet->fonts[i];
287
288       FontPath path;
289
290       // Skip fonts with no path
291       if( GetFcString( fontPattern, FC_FILE, path ) )
292       {
293         fontList.push_back( FontDescription() );
294         FontDescription& newFontDescription = fontList.back();
295
296         newFontDescription.path = path;
297
298         int width = 0;
299         int weight = 0;
300         int slant = 0;
301         GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
302         GetFcInt( fontPattern, FC_WIDTH, width );
303         GetFcInt( fontPattern, FC_WEIGHT, weight );
304         GetFcInt( fontPattern, FC_SLANT, slant );
305         newFontDescription.width = IntToWidthType( width );
306         newFontDescription.weight = IntToWeightType( weight );
307         newFontDescription.slant = IntToSlantType( slant );
308       }
309     }
310
311     FcFontSetDestroy( fontSet );
312   }
313
314   FcPatternDestroy( fontFamilyPattern );
315 }
316
317 void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
318 {
319   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
320
321   if( mDefaultFonts.empty() )
322   {
323     FontDescription fontDescription;
324     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
325     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
326     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
327     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
328     SetFontList( fontDescription, mDefaultFonts );
329   }
330
331   defaultFonts = mDefaultFonts;
332 }
333
334 void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
335 {
336   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
337
338   if( !mDefaultFontDescriptionCached )
339   {
340     FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
341
342     FcPattern* matchPattern = FcPatternCreate();
343
344     if( matchPattern )
345     {
346       FcConfigSubstitute( NULL, matchPattern, FcMatchPattern );
347       FcDefaultSubstitute( matchPattern );
348
349       MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription );
350       FcPatternDestroy( matchPattern );
351     }
352
353     mDefaultFontDescriptionCached = true;
354   }
355
356   fontDescription.path   = mDefaultFontDescription.path;
357   fontDescription.family = mDefaultFontDescription.family;
358   fontDescription.width  = mDefaultFontDescription.width;
359   fontDescription.weight = mDefaultFontDescription.weight;
360   fontDescription.slant  = mDefaultFontDescription.slant;
361 }
362
363 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
364 {
365   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
366
367   if( mSystemFonts.empty() )
368   {
369     InitSystemFonts();
370   }
371
372   systemFonts = mSystemFonts;
373 }
374
375 void FontClient::Plugin::GetDescription( FontId id,
376                                          FontDescription& fontDescription ) const
377 {
378   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
379          endIt = mFontIdCache.end();
380        it != endIt;
381        ++it )
382   {
383     const FontIdCacheItem& item = *it;
384
385     if( item.fontId == id )
386     {
387       fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
388       return;
389     }
390   }
391
392   DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
393 }
394
395 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
396 {
397   const FontId index = id - 1u;
398
399   if( id > 0u &&
400       index < mFontCache.size() )
401   {
402     return ( *( mFontCache.begin() + index ) ).mRequestedPointSize;
403   }
404   else
405   {
406     DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
407   }
408
409   return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
410 }
411
412 FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
413                                                  Character charcode,
414                                                  PointSize26Dot6 requestedPointSize,
415                                                  bool preferColor )
416 {
417   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFontForCharacter\n");
418
419   FontId fontId = 0u;
420   bool foundColor = false;
421
422   // Traverse the list of fonts.
423   // Check for each font if supports the character.
424   for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end();
425        it != endIt;
426        ++it )
427   {
428     const FontDescription& description = *it;
429
430     FcPattern* pattern = CreateFontFamilyPattern( description );
431
432     FcResult result = FcResultMatch;
433     FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
434
435     FcCharSet* charSet = NULL;
436     FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
437
438     if( FcCharSetHasChar( charSet, charcode ) )
439     {
440       Vector< PointSize26Dot6 > fixedSizes;
441       GetFixedSizes( description,
442                      fixedSizes );
443
444       PointSize26Dot6 actualPointSize = requestedPointSize;
445
446       const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
447
448       if( 0 != count )
449       {
450         // If the font is not scalable, pick the largest size <= requestedPointSize
451         actualPointSize = fixedSizes[0];
452         for( unsigned int i=1; i<count; ++i )
453         {
454           if( fixedSizes[i] <= requestedPointSize &&
455               fixedSizes[i] > actualPointSize )
456           {
457             actualPointSize = fixedSizes[i];
458           }
459         }
460       }
461
462       fontId = GetFontId( description,
463                           requestedPointSize,
464                           actualPointSize,
465                           0u );
466
467       if( preferColor )
468       {
469         foundColor = IsColorGlyph( fontId, GetGlyphIndex( fontId, charcode ) );
470       }
471
472       // Keep going unless we prefer a different (color) font.
473       if( !preferColor || foundColor )
474       {
475         FcPatternDestroy( match );
476         FcPatternDestroy( pattern );
477         break;
478       }
479     }
480
481     FcPatternDestroy( match );
482     FcPatternDestroy( pattern );
483   }
484
485   return fontId;
486 }
487
488 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
489                                             PointSize26Dot6 requestedPointSize,
490                                             bool preferColor )
491 {
492   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
493
494   FontId fontId(0);
495
496   // Create the list of default fonts if it has not been created.
497   if( mDefaultFonts.empty() )
498   {
499     FontDescription fontDescription;
500     fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
501     fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
502     fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
503     fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
504
505     SetFontList( fontDescription, mDefaultFonts );
506   }
507
508   // Traverse the list of default fonts.
509   // Check for each default font if supports the character.
510   fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedPointSize, preferColor );
511
512   return fontId;
513 }
514
515 FontId FontClient::Plugin::FindFallbackFont( Character charcode,
516                                              const FontDescription& preferredFontDescription,
517                                              PointSize26Dot6 requestedPointSize,
518                                              bool preferColor )
519 {
520   // The font id to be returned.
521   FontId fontId = 0u;
522
523   FontDescription fontDescription;
524
525   // Fill the font description with the preferred font description and complete with the defaults.
526   fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
527   fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
528   fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
529   fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
530
531   // Check first if the font's description has been queried before.
532   FontList* fontList( NULL );
533
534   if( !FindFallbackFontList( fontDescription, fontList ) )
535   {
536     fontList = new FontList;
537     SetFontList( fontDescription, *fontList );
538
539     // Add the font-list to the cache.
540     mFallbackCache.push_back( FallbackCacheItem( fontDescription, fontList ) );
541   }
542
543   if( fontList )
544   {
545     fontId = FindFontForCharacter( *fontList, charcode, requestedPointSize, preferColor );
546   }
547
548   return fontId;
549 }
550
551 FontId FontClient::Plugin::GetFontId( const FontPath& path,
552                                       PointSize26Dot6 requestedPointSize,
553                                       PointSize26Dot6 actualPointSize,
554                                       FaceIndex faceIndex,
555                                       bool cacheDescription )
556 {
557   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
558
559   FontId id( 0 );
560
561   if( NULL != mFreeTypeLibrary )
562   {
563     FontId foundId(0);
564     if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
565     {
566       id = foundId;
567     }
568     else
569     {
570       id = CreateFont( path, requestedPointSize, actualPointSize, faceIndex, cacheDescription );
571     }
572   }
573
574   return id;
575 }
576
577 FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
578                                       PointSize26Dot6 requestedPointSize,
579                                       PointSize26Dot6 actualPointSize,
580                                       FaceIndex faceIndex )
581 {
582   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() );
583
584   // This method uses three vectors which caches:
585   // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
586   // * The path to font file names.
587   // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
588
589   // 1) Checks in the cache if the font's description has been validated before.
590   //    If it was it gets an index to the vector with paths to font file names. Otherwise,
591   //    retrieves using font config a path to a font file name which matches with the
592   //    font's description. The path is stored in the cache.
593   //
594   // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
595   //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
596   //    the GetFontId() method with the path to the font file name and the point size to
597   //    get the font id.
598
599   // The font id to be returned.
600   FontId fontId = 0u;
601
602   // Check first if the font's description have been validated before.
603   FontDescriptionId validatedFontId = 0u;
604
605   if( !FindValidatedFont( fontDescription,
606                           validatedFontId ) )
607   {
608     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n");
609
610     // Use font config to validate the font's description.
611     ValidateFont( fontDescription,
612                   validatedFontId );
613   }
614
615   // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
616   if( !FindFont( validatedFontId, requestedPointSize, fontId ) )
617   {
618     // Retrieve the font file name path.
619     const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
620
621     // Retrieve the font id. Do not cache the description as it has been already cached.
622     fontId = GetFontId( description.path,
623                         requestedPointSize,
624                         actualPointSize,
625                         faceIndex,
626                         false );
627
628     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
629     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
630                                              requestedPointSize,
631                                              fontId ) );
632   }
633
634   return fontId;
635 }
636
637 void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
638                                        FontDescriptionId& validatedFontId )
639 {
640   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
641
642   // Create a font pattern.
643   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
644
645   FontDescription description;
646
647   bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description );
648   FcPatternDestroy( fontFamilyPattern );
649
650   if( matched )
651   {
652     // Set the index to the vector of paths to font file names.
653     validatedFontId = mFontDescriptionCache.size();
654
655     // Add the path to the cache.
656     mFontDescriptionCache.push_back( description );
657
658     // Cache the index and the matched font's description.
659     FontDescriptionCacheItem item( description,
660                                    validatedFontId );
661
662     mValidatedFontCache.push_back( item );
663
664     if( ( fontDescription.family != description.family ) ||
665         ( fontDescription.width != description.width )   ||
666         ( fontDescription.weight != description.weight ) ||
667         ( fontDescription.slant != description.slant ) )
668     {
669       // Cache the given font's description if it's different than the matched.
670       FontDescriptionCacheItem item( fontDescription,
671                                      validatedFontId );
672
673       mValidatedFontCache.push_back( item );
674     }
675   }
676   else
677   {
678     DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
679                     fontDescription.family.c_str(),
680                     fontDescription.width,
681                     fontDescription.weight,
682                     fontDescription.slant );
683   }
684
685   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() );
686 }
687
688 void FontClient::Plugin::GetFontMetrics( FontId fontId,
689                                          FontMetrics& metrics )
690 {
691   if( ( fontId > 0 ) &&
692       ( fontId - 1u < mFontCache.size() ) )
693   {
694     const FontFaceCacheItem& font = mFontCache[fontId-1];
695
696     metrics = font.mMetrics;
697
698     // Adjust the metrics if the fixed-size font should be down-scaled
699     if( font.mIsFixedSizeBitmap )
700     {
701       const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
702
703       if( desiredFixedSize > 0.f )
704       {
705         const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
706
707         metrics.ascender = floorf( metrics.ascender * scaleFactor );
708         metrics.descender = floorf( metrics.descender * scaleFactor );
709         metrics.height = floorf( metrics.height * scaleFactor );
710         metrics.underlinePosition = floorf( metrics.underlinePosition * scaleFactor );
711         metrics.underlineThickness = floorf( metrics.underlineThickness * scaleFactor );
712       }
713     }
714   }
715   else
716   {
717     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
718   }
719 }
720
721 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
722                                               Character charcode )
723 {
724   GlyphIndex index( 0 );
725
726   if( fontId > 0 &&
727       fontId-1 < mFontCache.size() )
728   {
729     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
730
731     index = FT_Get_Char_Index( ftFace, charcode );
732   }
733
734   return index;
735 }
736
737 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
738                                           uint32_t size,
739                                           GlyphType type,
740                                           bool horizontal )
741 {
742   if( VECTOR_GLYPH == type )
743   {
744     return GetVectorMetrics( array, size, horizontal );
745   }
746
747   return GetBitmapMetrics( array, size, horizontal );
748 }
749
750 bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
751                                            uint32_t size,
752                                            bool horizontal )
753 {
754   bool success( true );
755
756   for( unsigned int i=0; i<size; ++i )
757   {
758     GlyphInfo& glyph = array[i];
759
760     FontId fontId = glyph.fontId;
761
762     if( fontId > 0 &&
763         fontId-1 < mFontCache.size() )
764     {
765       const FontFaceCacheItem& font = mFontCache[fontId-1];
766
767       FT_Face ftFace = font.mFreeTypeFace;
768
769 #ifdef FREETYPE_BITMAP_SUPPORT
770       // Check to see if we should be loading a Fixed Size bitmap?
771       if ( font.mIsFixedSizeBitmap )
772       {
773         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
774         if ( FT_Err_Ok == error )
775         {
776           glyph.width = font.mFixedWidthPixels;
777           glyph.height = font.mFixedHeightPixels;
778           glyph.advance = font.mFixedWidthPixels;
779           glyph.xBearing = 0.0f;
780           glyph.yBearing = font.mFixedHeightPixels;
781
782           // Adjust the metrics if the fixed-size font should be down-scaled
783           const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
784
785           if( desiredFixedSize > 0.f )
786           {
787             const float scaleFactor = desiredFixedSize / static_cast<float>( font.mFixedHeightPixels );
788
789             glyph.width = floorf( glyph.width * scaleFactor );
790             glyph.height = floorf( glyph.height * scaleFactor );
791             glyph.advance = floorf( glyph.advance * scaleFactor );
792             glyph.xBearing = floorf( glyph.xBearing * scaleFactor );
793             glyph.yBearing = floorf( glyph.yBearing * scaleFactor );
794
795             glyph.scaleFactor = scaleFactor;
796           }
797         }
798         else
799         {
800           DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
801           success = false;
802         }
803       }
804       else
805 #endif
806       {
807         int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_DEFAULT );
808
809         if( FT_Err_Ok == error )
810         {
811           glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
812           glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
813           if( horizontal )
814           {
815             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
816             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
817           }
818           else
819           {
820             glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
821             glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
822           }
823         }
824         else
825         {
826           success = false;
827         }
828       }
829     }
830     else
831     {
832       success = false;
833     }
834   }
835
836   return success;
837 }
838
839 bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
840                                            uint32_t size,
841                                            bool horizontal )
842 {
843 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
844   bool success( true );
845
846   for( unsigned int i=0; i<size; ++i )
847   {
848     FontId fontId = array[i].fontId;
849
850     if( fontId > 0 &&
851         fontId-1 < mFontCache.size() )
852     {
853       FontFaceCacheItem& font = mFontCache[fontId-1];
854
855       if( ! font.mVectorFontId )
856       {
857         font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
858       }
859
860       mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
861
862       // Vector metrics are in EMs, convert to pixels
863       const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
864       array[i].width    *= scale;
865       array[i].height   *= scale;
866       array[i].xBearing *= scale;
867       array[i].yBearing *= scale;
868       array[i].advance  *= scale;
869     }
870     else
871     {
872       success = false;
873     }
874   }
875
876   return success;
877 #else
878   return false;
879 #endif
880 }
881
882 void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data )
883 {
884   if( ( fontId > 0 ) &&
885       ( fontId - 1u < mFontCache.size() ) )
886   {
887     FT_Face ftFace = mFontCache[fontId - 1u].mFreeTypeFace;
888
889     FT_Error error;
890
891 #ifdef FREETYPE_BITMAP_SUPPORT
892     // Check to see if this is fixed size bitmap
893     if ( mFontCache[fontId - 1u].mIsFixedSizeBitmap )
894     {
895       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
896     }
897     else
898 #endif
899     {
900       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
901     }
902     if( FT_Err_Ok == error )
903     {
904       FT_Glyph glyph;
905       error = FT_Get_Glyph( ftFace->glyph, &glyph );
906
907       // Convert to bitmap if necessary
908       if ( FT_Err_Ok == error )
909       {
910         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
911         {
912           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
913           if ( FT_Err_Ok == error )
914           {
915             FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
916             ConvertBitmap( data, bitmapGlyph->bitmap );
917           }
918           else
919           {
920             DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
921           }
922         }
923         else
924         {
925           ConvertBitmap( data, ftFace->glyph->bitmap );
926         }
927
928         // Created FT_Glyph object must be released with FT_Done_Glyph
929         FT_Done_Glyph( glyph );
930       }
931     }
932     else
933     {
934       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
935     }
936   }
937 }
938
939 PixelData FontClient::Plugin::CreateBitmap( FontId fontId,
940                                             GlyphIndex glyphIndex )
941 {
942   TextAbstraction::FontClient::GlyphBufferData data;
943
944   CreateBitmap( fontId, glyphIndex, data );
945
946   return PixelData::New( data.buffer,
947                          data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
948                          data.width,
949                          data.height,
950                          data.format,
951                          PixelData::DELETE_ARRAY );
952 }
953
954 void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
955 {
956   blob = NULL;
957   blobLength = 0;
958
959 #ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
960   if( fontId > 0 &&
961       fontId-1 < mFontCache.size() )
962   {
963     FontFaceCacheItem& font = mFontCache[fontId-1];
964
965     if( ! font.mVectorFontId )
966     {
967       font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
968     }
969
970     mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
971   }
972 #endif
973 }
974
975 const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
976 {
977   // First look into the cache if there is an ellipsis glyph for the requested point size.
978   for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
979          endIt = mEllipsisCache.End();
980        it != endIt;
981        ++it )
982   {
983     const EllipsisItem& item = *it;
984
985     if( fabsf( item.requestedPointSize - requestedPointSize ) < Math::MACHINE_EPSILON_1000 )
986     {
987       // Use the glyph in the cache.
988       return item.glyph;
989     }
990   }
991
992   // No glyph has been found. Create one.
993   mEllipsisCache.PushBack( EllipsisItem() );
994   EllipsisItem& item = *( mEllipsisCache.End() - 1u );
995
996   item.requestedPointSize = requestedPointSize;
997
998   // Find a font for the ellipsis glyph.
999   item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
1000                                        requestedPointSize,
1001                                        false );
1002
1003   // Set the character index to access the glyph inside the font.
1004   item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
1005                                         ELLIPSIS_CHARACTER );
1006
1007   GetBitmapMetrics( &item.glyph, 1u, true );
1008
1009   return item.glyph;
1010 }
1011
1012 bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
1013 {
1014   FT_Error error = -1;
1015
1016 #ifdef FREETYPE_BITMAP_SUPPORT
1017   if( ( fontId > 0 ) &&
1018       ( fontId - 1u < mFontCache.size() ) )
1019   {
1020     const FontFaceCacheItem& item = mFontCache[fontId - 1u];
1021     FT_Face ftFace = item.mFreeTypeFace;
1022
1023     // Check to see if this is fixed size bitmap
1024     if( item.mIsFixedSizeBitmap )
1025     {
1026       error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
1027     }
1028   }
1029 #endif
1030
1031   return FT_Err_Ok == error;
1032 }
1033
1034 void FontClient::Plugin::InitSystemFonts()
1035 {
1036   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
1037
1038   FcFontSet* fontSet = GetFcFontSet();
1039
1040   if( fontSet )
1041   {
1042     // Reserve some space to avoid reallocations.
1043     mSystemFonts.reserve( fontSet->nfont );
1044
1045     for( int i = 0u; i < fontSet->nfont; ++i )
1046     {
1047       FcPattern* fontPattern = fontSet->fonts[i];
1048
1049       FontPath path;
1050
1051       // Skip fonts with no path
1052       if( GetFcString( fontPattern, FC_FILE, path ) )
1053       {
1054         mSystemFonts.push_back( FontDescription() );
1055         FontDescription& fontDescription = mSystemFonts.back();
1056
1057         fontDescription.path = path;
1058
1059         int width = 0;
1060         int weight = 0;
1061         int slant = 0;
1062         GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
1063         GetFcInt( fontPattern, FC_WIDTH, width );
1064         GetFcInt( fontPattern, FC_WEIGHT, weight );
1065         GetFcInt( fontPattern, FC_SLANT, slant );
1066         fontDescription.width = IntToWidthType( width );
1067         fontDescription.weight = IntToWeightType( weight );
1068         fontDescription.slant = IntToSlantType( slant );
1069         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
1070
1071       }
1072     }
1073
1074     FcFontSetDestroy( fontSet );
1075   }
1076 }
1077
1078 bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription )
1079 {
1080   FcResult result = FcResultMatch;
1081   FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
1082
1083   bool ret = false;
1084
1085   if( match )
1086   {
1087     int width = 0;
1088     int weight = 0;
1089     int slant = 0;
1090     GetFcString( match, FC_FILE, fontDescription.path );
1091     GetFcString( match, FC_FAMILY, fontDescription.family );
1092     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str());
1093     GetFcInt( match, FC_WIDTH, width );
1094     GetFcInt( match, FC_WEIGHT, weight );
1095     GetFcInt( match, FC_SLANT, slant );
1096     fontDescription.width = IntToWidthType( width );
1097     fontDescription.weight = IntToWeightType( weight );
1098     fontDescription.slant = IntToSlantType( slant );
1099
1100     // destroyed the matched pattern
1101     FcPatternDestroy( match );
1102     ret = true;
1103   }
1104   return ret;
1105 }
1106
1107
1108 FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
1109 {
1110   // create the cached font family lookup pattern
1111   // a pattern holds a set of names, each name refers to a property of the font
1112   FcPattern* fontFamilyPattern = FcPatternCreate();
1113
1114   if( !fontFamilyPattern )
1115   {
1116     return NULL;
1117   }
1118
1119   // add a property to the pattern for the font family
1120   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1121
1122   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1123   if( width < 0 )
1124   {
1125     // Use default.
1126     width = DEFAULT_FONT_WIDTH;
1127   }
1128
1129   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1130   if( weight < 0 )
1131   {
1132     // Use default.
1133     weight = DEFAULT_FONT_WEIGHT;
1134   }
1135
1136   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1137   if( slant < 0 )
1138   {
1139     // Use default.
1140     slant = DEFAULT_FONT_SLANT;
1141   }
1142
1143   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1144   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1145   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1146
1147   // Add a property of the pattern, to say we want to match TrueType fonts
1148   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1149
1150   // modify the config, with the mFontFamilyPatterm
1151   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1152
1153   // provide default values for unspecified properties in the font pattern
1154   // e.g. patterns without a specified style or weight are set to Medium
1155   FcDefaultSubstitute( fontFamilyPattern );
1156
1157   return fontFamilyPattern;
1158 }
1159
1160 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1161 {
1162   // create a new pattern.
1163   // a pattern holds a set of names, each name refers to a property of the font
1164   FcPattern* pattern = FcPatternCreate();
1165
1166   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1167   FcObjectSet* objectSet = FcObjectSetCreate();
1168
1169   // build an object set from a list of property names
1170   FcObjectSetAdd( objectSet, FC_FILE );
1171   FcObjectSetAdd( objectSet, FC_FAMILY );
1172   FcObjectSetAdd( objectSet, FC_WIDTH );
1173   FcObjectSetAdd( objectSet, FC_WEIGHT );
1174   FcObjectSetAdd( objectSet, FC_SLANT );
1175
1176   // get a list of fonts
1177   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1178   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1179
1180   // clear up the object set
1181   if( objectSet )
1182   {
1183     FcObjectSetDestroy( objectSet );
1184   }
1185   // clear up the pattern
1186   if( pattern )
1187   {
1188     FcPatternDestroy( pattern );
1189   }
1190
1191   return fontset;
1192 }
1193
1194 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1195                                       const char* const n,
1196                                       std::string& string )
1197 {
1198   FcChar8* file = NULL;
1199   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1200
1201   if( FcResultMatch == retVal )
1202   {
1203     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1204     string.assign( reinterpret_cast<const char*>( file ) );
1205
1206     return true;
1207   }
1208
1209   return false;
1210 }
1211
1212 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1213 {
1214   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1215
1216   if( FcResultMatch == retVal )
1217   {
1218     return true;
1219   }
1220
1221   return false;
1222 }
1223
1224 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1225                                        PointSize26Dot6 requestedPointSize,
1226                                        PointSize26Dot6 actualPointSize,
1227                                        FaceIndex faceIndex,
1228                                        bool cacheDescription )
1229 {
1230   FontId id( 0 );
1231
1232   // Create & cache new font face
1233   FT_Face ftFace;
1234   int error = FT_New_Face( mFreeTypeLibrary,
1235                            path.c_str(),
1236                            0,
1237                            &ftFace );
1238
1239   if( FT_Err_Ok == error )
1240   {
1241     // Check to see if the font contains fixed sizes?
1242     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1243     {
1244       // Ensure this size is available
1245       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1246       {
1247         if ( static_cast<FT_Pos>( actualPointSize ) == ftFace->available_sizes[ i ].size )
1248         {
1249           // Tell Freetype to use this size
1250           error = FT_Select_Size( ftFace, i );
1251           if ( FT_Err_Ok != error )
1252           {
1253             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1254           }
1255           else
1256           {
1257             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
1258             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1259
1260             // Indicate that the font is a fixed sized bitmap
1261             FontMetrics metrics( fixedHeight, // The ascender in pixels.
1262                                  0.0f,
1263                                  fixedHeight, // The height in pixels.
1264                                  0.0f,
1265                                  0.0f );
1266
1267             mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1268             id = mFontCache.size();
1269
1270             if( cacheDescription )
1271             {
1272               CacheFontPath( ftFace, id, requestedPointSize, path );
1273             }
1274
1275             return id;
1276           }
1277         }
1278       }
1279
1280       // Can't find this size
1281       std::stringstream sizes;
1282       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1283       {
1284         if ( i )
1285         {
1286           sizes << ", ";
1287         }
1288         sizes << ftFace->available_sizes[ i ].size;
1289       }
1290       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1291                        path.c_str(), actualPointSize, sizes.str().c_str() );
1292     }
1293     else
1294     {
1295       error = FT_Set_Char_Size( ftFace,
1296                                 0,
1297                                 actualPointSize,
1298                                 mDpiHorizontal,
1299                                 mDpiVertical );
1300
1301       if( FT_Err_Ok == error )
1302       {
1303
1304         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1305
1306         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1307                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1308                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1309                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1310                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1311
1312         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1313         id = mFontCache.size();
1314
1315         if( cacheDescription )
1316         {
1317           CacheFontPath( ftFace, id, requestedPointSize, path );
1318         }
1319       }
1320       else
1321       {
1322         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, actualPointSize );
1323       }
1324     }
1325   }
1326   else
1327   {
1328     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1329   }
1330
1331   return id;
1332 }
1333
1334 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1335 {
1336   if( srcBitmap.width*srcBitmap.rows > 0 )
1337   {
1338     switch( srcBitmap.pixel_mode )
1339     {
1340       case FT_PIXEL_MODE_GRAY:
1341       {
1342         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1343         {
1344           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1345           data.buffer = new unsigned char[bufferSize];
1346           data.width = srcBitmap.width;
1347           data.height = srcBitmap.rows;
1348           data.format = Pixel::L8;
1349           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1350         }
1351         break;
1352       }
1353
1354 #ifdef FREETYPE_BITMAP_SUPPORT
1355       case FT_PIXEL_MODE_BGRA:
1356       {
1357         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1358         {
1359           // Set the input dimensions.
1360           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1361
1362           // Set the output dimensions.
1363           // If the output dimension is not given, the input dimension is set
1364           // and won't be downscaling.
1365           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1366           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1367           const ImageDimensions desiredDimensions( data.width, data.height );
1368
1369           // Creates the output buffer
1370           const unsigned int bufferSize = data.width * data.height * 4u;
1371           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1372
1373           if( inputDimensions == desiredDimensions )
1374           {
1375             // There isn't downscaling.
1376             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1377           }
1378           else
1379           {
1380             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1381                                                          inputDimensions,
1382                                                          data.buffer,
1383                                                          desiredDimensions );
1384           }
1385           data.format = Pixel::BGRA8888;
1386         }
1387         break;
1388       }
1389 #endif
1390       default:
1391       {
1392         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1393         break;
1394       }
1395     }
1396   }
1397 }
1398
1399 bool FontClient::Plugin::FindFont( const FontPath& path,
1400                                    PointSize26Dot6 requestedPointSize,
1401                                    FaceIndex faceIndex,
1402                                    FontId& fontId ) const
1403 {
1404   fontId = 0u;
1405   for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1406          endIt = mFontCache.end();
1407        it != endIt;
1408        ++it, ++fontId )
1409   {
1410     const FontFaceCacheItem& cacheItem = *it;
1411
1412     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1413         cacheItem.mFaceIndex == faceIndex &&
1414         cacheItem.mPath == path )
1415     {
1416       ++fontId;
1417       return true;
1418     }
1419   }
1420
1421   return false;
1422 }
1423
1424 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1425                                             FontDescriptionId& validatedFontId )
1426 {
1427   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1428
1429   validatedFontId = 0u;
1430
1431   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1432          endIt = mValidatedFontCache.end();
1433        it != endIt;
1434        ++it )
1435   {
1436     const FontDescriptionCacheItem& item = *it;
1437
1438     if( !fontDescription.family.empty() &&
1439         ( fontDescription.family == item.fontDescription.family ) &&
1440         ( fontDescription.width == item.fontDescription.width ) &&
1441         ( fontDescription.weight == item.fontDescription.weight ) &&
1442         ( fontDescription.slant == item.fontDescription.slant ) )
1443     {
1444       validatedFontId = item.index;
1445
1446       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1447
1448       return true;
1449     }
1450   }
1451
1452   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1453
1454   return false;
1455 }
1456
1457 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1458                                                FontList*& fontList )
1459 {
1460   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1461
1462   fontList = NULL;
1463
1464   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1465        it != endIt;
1466        ++it )
1467   {
1468     const FallbackCacheItem& item = *it;
1469
1470     if( !fontDescription.family.empty() &&
1471         ( fontDescription.family == item.fontDescription.family ) &&
1472         ( fontDescription.width == item.fontDescription.width ) &&
1473         ( fontDescription.weight == item.fontDescription.weight ) &&
1474         ( fontDescription.slant == item.fontDescription.slant ) )
1475     {
1476       fontList = item.fallbackFonts;
1477
1478       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1479
1480       return true;
1481     }
1482   }
1483
1484   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1485
1486   return false;
1487 }
1488
1489 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1490                                    PointSize26Dot6 requestedPointSize,
1491                                    FontId& fontId )
1492 {
1493   fontId = 0u;
1494
1495   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1496          endIt = mFontIdCache.end();
1497        it != endIt;
1498        ++it )
1499   {
1500     const FontIdCacheItem& item = *it;
1501
1502     if( ( validatedFontId == item.validatedFontId ) &&
1503         ( requestedPointSize == item.requestedPointSize ) )
1504     {
1505       fontId = item.fontId;
1506       return true;
1507     }
1508   }
1509
1510   return false;
1511 }
1512
1513 bool FontClient::Plugin::IsScalable( const FontPath& path )
1514 {
1515   FT_Face ftFace;
1516   int error = FT_New_Face( mFreeTypeLibrary,
1517                            path.c_str(),
1518                            0,
1519                            &ftFace );
1520   if( FT_Err_Ok != error )
1521   {
1522     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1523   }
1524   return ( ftFace->num_fixed_sizes == 0 );
1525 }
1526
1527 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1528 {
1529   // Create a font pattern.
1530   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1531
1532   FcResult result = FcResultMatch;
1533
1534   // match the pattern
1535   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1536   bool isScalable = true;
1537
1538   if( match )
1539   {
1540     // Get the path to the font file name.
1541     FontPath path;
1542     GetFcString( match, FC_FILE, path );
1543     isScalable = IsScalable( path );
1544   }
1545   else
1546   {
1547     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1548                     fontDescription.family.c_str(),
1549                     fontDescription.width,
1550                     fontDescription.weight,
1551                     fontDescription.slant );
1552   }
1553   FcPatternDestroy( fontFamilyPattern );
1554   FcPatternDestroy( match );
1555   return isScalable;
1556 }
1557
1558 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1559 {
1560   // Empty the caller container
1561   sizes.Clear();
1562
1563   FT_Face ftFace;
1564   int error = FT_New_Face( mFreeTypeLibrary,
1565                            path.c_str(),
1566                            0,
1567                            &ftFace );
1568   if( FT_Err_Ok != error )
1569   {
1570     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1571   }
1572
1573   // Fetch the number of fixed sizes available
1574   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1575   {
1576     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1577     {
1578       sizes.PushBack( ftFace->available_sizes[ i ].size );
1579     }
1580   }
1581 }
1582
1583 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1584                                         Vector< PointSize26Dot6 >& sizes )
1585 {
1586   // Create a font pattern.
1587   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1588
1589   FcResult result = FcResultMatch;
1590
1591   // match the pattern
1592   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1593
1594   if( match )
1595   {
1596     // Get the path to the font file name.
1597     FontPath path;
1598     GetFcString( match, FC_FILE, path );
1599     GetFixedSizes( path, sizes );
1600   }
1601   else
1602   {
1603     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1604                     fontDescription.family.c_str(),
1605                     fontDescription.width,
1606                     fontDescription.weight,
1607                     fontDescription.slant );
1608   }
1609   FcPatternDestroy( match );
1610   FcPatternDestroy( fontFamilyPattern );
1611 }
1612
1613 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1614 {
1615   FontDescription description;
1616   description.path = path;
1617   description.family = FontFamily( ftFace->family_name );
1618   description.weight = FontWeight::NONE;
1619   description.width = FontWidth::NONE;
1620   description.slant = FontSlant::NONE;
1621
1622   // Note FreeType doesn't give too much info to build a proper font style.
1623   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1624   {
1625     description.slant = FontSlant::ITALIC;
1626   }
1627   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1628   {
1629     description.weight = FontWeight::BOLD;
1630   }
1631
1632   FontDescriptionId validatedFontId = 0u;
1633   if( !FindValidatedFont( description,
1634                           validatedFontId ) )
1635   {
1636     // Set the index to the vector of paths to font file names.
1637     validatedFontId = mFontDescriptionCache.size();
1638
1639     // Add the path to the cache.
1640     mFontDescriptionCache.push_back( description );
1641
1642     // Cache the index and the font's description.
1643     FontDescriptionCacheItem item( description,
1644                                    validatedFontId );
1645
1646     mValidatedFontCache.push_back( item );
1647
1648     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1649     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1650                                              requestedPointSize,
1651                                              id ) );
1652   }
1653 }
1654
1655 } // namespace Internal
1656
1657 } // namespace TextAbstraction
1658
1659 } // namespace Dali