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