68399fceb737700d0c7a0130d7ba15ff5c5da9fe
[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   // add a property to the pattern for the font family
1111   FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
1112
1113   int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
1114   if( width < 0 )
1115   {
1116     // Use default.
1117     width = DEFAULT_FONT_WIDTH;
1118   }
1119
1120   int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
1121   if( weight < 0 )
1122   {
1123     // Use default.
1124     weight = DEFAULT_FONT_WEIGHT;
1125   }
1126
1127   int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
1128   if( slant < 0 )
1129   {
1130     // Use default.
1131     slant = DEFAULT_FONT_SLANT;
1132   }
1133
1134   FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
1135   FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
1136   FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
1137
1138   // Add a property of the pattern, to say we want to match TrueType fonts
1139   FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
1140
1141   // modify the config, with the mFontFamilyPatterm
1142   FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
1143
1144   // provide default values for unspecified properties in the font pattern
1145   // e.g. patterns without a specified style or weight are set to Medium
1146   FcDefaultSubstitute( fontFamilyPattern );
1147
1148   return fontFamilyPattern;
1149 }
1150
1151 _FcFontSet* FontClient::Plugin::GetFcFontSet() const
1152 {
1153   // create a new pattern.
1154   // a pattern holds a set of names, each name refers to a property of the font
1155   FcPattern* pattern = FcPatternCreate();
1156
1157   // create an object set used to define which properties are to be returned in the patterns from FcFontList.
1158   FcObjectSet* objectSet = FcObjectSetCreate();
1159
1160   // build an object set from a list of property names
1161   FcObjectSetAdd( objectSet, FC_FILE );
1162   FcObjectSetAdd( objectSet, FC_FAMILY );
1163   FcObjectSetAdd( objectSet, FC_WIDTH );
1164   FcObjectSetAdd( objectSet, FC_WEIGHT );
1165   FcObjectSetAdd( objectSet, FC_SLANT );
1166
1167   // get a list of fonts
1168   // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
1169   FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
1170
1171   // clear up the object set
1172   if( objectSet )
1173   {
1174     FcObjectSetDestroy( objectSet );
1175   }
1176   // clear up the pattern
1177   if( pattern )
1178   {
1179     FcPatternDestroy( pattern );
1180   }
1181
1182   return fontset;
1183 }
1184
1185 bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
1186                                       const char* const n,
1187                                       std::string& string )
1188 {
1189   FcChar8* file = NULL;
1190   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
1191
1192   if( FcResultMatch == retVal )
1193   {
1194     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
1195     string.assign( reinterpret_cast<const char*>( file ) );
1196
1197     return true;
1198   }
1199
1200   return false;
1201 }
1202
1203 bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
1204 {
1205   const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
1206
1207   if( FcResultMatch == retVal )
1208   {
1209     return true;
1210   }
1211
1212   return false;
1213 }
1214
1215 FontId FontClient::Plugin::CreateFont( const FontPath& path,
1216                                        PointSize26Dot6 requestedPointSize,
1217                                        PointSize26Dot6 actualPointSize,
1218                                        FaceIndex faceIndex,
1219                                        bool cacheDescription )
1220 {
1221   FontId id( 0 );
1222
1223   // Create & cache new font face
1224   FT_Face ftFace;
1225   int error = FT_New_Face( mFreeTypeLibrary,
1226                            path.c_str(),
1227                            0,
1228                            &ftFace );
1229
1230   if( FT_Err_Ok == error )
1231   {
1232     // Check to see if the font contains fixed sizes?
1233     if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1234     {
1235       // Ensure this size is available
1236       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1237       {
1238         if ( static_cast<FT_Pos>( actualPointSize ) == ftFace->available_sizes[ i ].size )
1239         {
1240           // Tell Freetype to use this size
1241           error = FT_Select_Size( ftFace, i );
1242           if ( FT_Err_Ok != error )
1243           {
1244             DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
1245           }
1246           else
1247           {
1248             float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
1249             float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
1250
1251             // Indicate that the font is a fixed sized bitmap
1252             FontMetrics metrics( fixedHeight, // The ascender in pixels.
1253                                  0.0f,
1254                                  fixedHeight, // The height in pixels.
1255                                  0.0f,
1256                                  0.0f );
1257
1258             mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
1259             id = mFontCache.size();
1260
1261             if( cacheDescription )
1262             {
1263               CacheFontPath( ftFace, id, requestedPointSize, path );
1264             }
1265
1266             return id;
1267           }
1268         }
1269       }
1270
1271       // Can't find this size
1272       std::stringstream sizes;
1273       for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1274       {
1275         if ( i )
1276         {
1277           sizes << ", ";
1278         }
1279         sizes << ftFace->available_sizes[ i ].size;
1280       }
1281       DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
1282                        path.c_str(), actualPointSize, sizes.str().c_str() );
1283     }
1284     else
1285     {
1286       error = FT_Set_Char_Size( ftFace,
1287                                 0,
1288                                 actualPointSize,
1289                                 mDpiHorizontal,
1290                                 mDpiVertical );
1291
1292       if( FT_Err_Ok == error )
1293       {
1294
1295         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
1296
1297         FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
1298                              static_cast< float >( ftMetrics.descender ) * FROM_266,
1299                              static_cast< float >( ftMetrics.height    ) * FROM_266,
1300                              static_cast< float >( ftFace->underline_position ) * FROM_266,
1301                              static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
1302
1303         mFontCache.push_back( FontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics ) );
1304         id = mFontCache.size();
1305
1306         if( cacheDescription )
1307         {
1308           CacheFontPath( ftFace, id, requestedPointSize, path );
1309         }
1310       }
1311       else
1312       {
1313         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, actualPointSize );
1314       }
1315     }
1316   }
1317   else
1318   {
1319     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
1320   }
1321
1322   return id;
1323 }
1324
1325 void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap )
1326 {
1327   if( srcBitmap.width*srcBitmap.rows > 0 )
1328   {
1329     switch( srcBitmap.pixel_mode )
1330     {
1331       case FT_PIXEL_MODE_GRAY:
1332       {
1333         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
1334         {
1335           const unsigned int bufferSize = srcBitmap.width * srcBitmap.rows;
1336           data.buffer = new unsigned char[bufferSize];
1337           data.width = srcBitmap.width;
1338           data.height = srcBitmap.rows;
1339           data.format = Pixel::L8;
1340           memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1341         }
1342         break;
1343       }
1344
1345 #ifdef FREETYPE_BITMAP_SUPPORT
1346       case FT_PIXEL_MODE_BGRA:
1347       {
1348         if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
1349         {
1350           // Set the input dimensions.
1351           const ImageDimensions inputDimensions( srcBitmap.width, srcBitmap.rows );
1352
1353           // Set the output dimensions.
1354           // If the output dimension is not given, the input dimension is set
1355           // and won't be downscaling.
1356           data.width = ( data.width == 0 ) ? srcBitmap.width : data.width;
1357           data.height = ( data.height == 0 ) ? srcBitmap.rows : data.height;
1358           const ImageDimensions desiredDimensions( data.width, data.height );
1359
1360           // Creates the output buffer
1361           const unsigned int bufferSize = data.width * data.height * 4u;
1362           data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
1363
1364           if( inputDimensions == desiredDimensions )
1365           {
1366             // There isn't downscaling.
1367             memcpy( data.buffer, srcBitmap.buffer, bufferSize );
1368           }
1369           else
1370           {
1371             Dali::Internal::Platform::LanczosSample4BPP( srcBitmap.buffer,
1372                                                          inputDimensions,
1373                                                          data.buffer,
1374                                                          desiredDimensions );
1375           }
1376           data.format = Pixel::BGRA8888;
1377         }
1378         break;
1379       }
1380 #endif
1381       default:
1382       {
1383         DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
1384         break;
1385       }
1386     }
1387   }
1388 }
1389
1390 bool FontClient::Plugin::FindFont( const FontPath& path,
1391                                    PointSize26Dot6 requestedPointSize,
1392                                    FaceIndex faceIndex,
1393                                    FontId& fontId ) const
1394 {
1395   fontId = 0u;
1396   for( std::vector<FontFaceCacheItem>::const_iterator it = mFontCache.begin(),
1397          endIt = mFontCache.end();
1398        it != endIt;
1399        ++it, ++fontId )
1400   {
1401     const FontFaceCacheItem& cacheItem = *it;
1402
1403     if( cacheItem.mRequestedPointSize == requestedPointSize &&
1404         cacheItem.mFaceIndex == faceIndex &&
1405         cacheItem.mPath == path )
1406     {
1407       ++fontId;
1408       return true;
1409     }
1410   }
1411
1412   return false;
1413 }
1414
1415 bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
1416                                             FontDescriptionId& validatedFontId )
1417 {
1418   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
1419
1420   validatedFontId = 0u;
1421
1422   for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
1423          endIt = mValidatedFontCache.end();
1424        it != endIt;
1425        ++it )
1426   {
1427     const FontDescriptionCacheItem& item = *it;
1428
1429     if( !fontDescription.family.empty() &&
1430         ( fontDescription.family == item.fontDescription.family ) &&
1431         ( fontDescription.width == item.fontDescription.width ) &&
1432         ( fontDescription.weight == item.fontDescription.weight ) &&
1433         ( fontDescription.slant == item.fontDescription.slant ) )
1434     {
1435       validatedFontId = item.index;
1436
1437       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
1438
1439       return true;
1440     }
1441   }
1442
1443   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
1444
1445   return false;
1446 }
1447
1448 bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
1449                                                FontList*& fontList )
1450 {
1451   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
1452
1453   fontList = NULL;
1454
1455   for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
1456        it != endIt;
1457        ++it )
1458   {
1459     const FallbackCacheItem& item = *it;
1460
1461     if( !fontDescription.family.empty() &&
1462         ( fontDescription.family == item.fontDescription.family ) &&
1463         ( fontDescription.width == item.fontDescription.width ) &&
1464         ( fontDescription.weight == item.fontDescription.weight ) &&
1465         ( fontDescription.slant == item.fontDescription.slant ) )
1466     {
1467       fontList = item.fallbackFonts;
1468
1469       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
1470
1471       return true;
1472     }
1473   }
1474
1475   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
1476
1477   return false;
1478 }
1479
1480 bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
1481                                    PointSize26Dot6 requestedPointSize,
1482                                    FontId& fontId )
1483 {
1484   fontId = 0u;
1485
1486   for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
1487          endIt = mFontIdCache.end();
1488        it != endIt;
1489        ++it )
1490   {
1491     const FontIdCacheItem& item = *it;
1492
1493     if( ( validatedFontId == item.validatedFontId ) &&
1494         ( requestedPointSize == item.requestedPointSize ) )
1495     {
1496       fontId = item.fontId;
1497       return true;
1498     }
1499   }
1500
1501   return false;
1502 }
1503
1504 bool FontClient::Plugin::IsScalable( const FontPath& path )
1505 {
1506   FT_Face ftFace;
1507   int error = FT_New_Face( mFreeTypeLibrary,
1508                            path.c_str(),
1509                            0,
1510                            &ftFace );
1511   if( FT_Err_Ok != error )
1512   {
1513     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1514   }
1515   return ( ftFace->num_fixed_sizes == 0 );
1516 }
1517
1518 bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
1519 {
1520   // Create a font pattern.
1521   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1522
1523   FcResult result = FcResultMatch;
1524
1525   // match the pattern
1526   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1527   bool isScalable = true;
1528
1529   if( match )
1530   {
1531     // Get the path to the font file name.
1532     FontPath path;
1533     GetFcString( match, FC_FILE, path );
1534     isScalable = IsScalable( path );
1535   }
1536   else
1537   {
1538     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1539                     fontDescription.family.c_str(),
1540                     fontDescription.width,
1541                     fontDescription.weight,
1542                     fontDescription.slant );
1543   }
1544   FcPatternDestroy( fontFamilyPattern );
1545   FcPatternDestroy( match );
1546   return isScalable;
1547 }
1548
1549 void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
1550 {
1551   // Empty the caller container
1552   sizes.Clear();
1553
1554   FT_Face ftFace;
1555   int error = FT_New_Face( mFreeTypeLibrary,
1556                            path.c_str(),
1557                            0,
1558                            &ftFace );
1559   if( FT_Err_Ok != error )
1560   {
1561     DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
1562   }
1563
1564   // Fetch the number of fixed sizes available
1565   if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
1566   {
1567     for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
1568     {
1569       sizes.PushBack( ftFace->available_sizes[ i ].size );
1570     }
1571   }
1572 }
1573
1574 void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
1575                                         Vector< PointSize26Dot6 >& sizes )
1576 {
1577   // Create a font pattern.
1578   FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
1579
1580   FcResult result = FcResultMatch;
1581
1582   // match the pattern
1583   FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
1584
1585   if( match )
1586   {
1587     // Get the path to the font file name.
1588     FontPath path;
1589     GetFcString( match, FC_FILE, path );
1590     GetFixedSizes( path, sizes );
1591   }
1592   else
1593   {
1594     DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
1595                     fontDescription.family.c_str(),
1596                     fontDescription.width,
1597                     fontDescription.weight,
1598                     fontDescription.slant );
1599   }
1600   FcPatternDestroy( match );
1601   FcPatternDestroy( fontFamilyPattern );
1602 }
1603
1604 void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
1605 {
1606   FontDescription description;
1607   description.path = path;
1608   description.family = FontFamily( ftFace->family_name );
1609   description.weight = FontWeight::NONE;
1610   description.width = FontWidth::NONE;
1611   description.slant = FontSlant::NONE;
1612
1613   // Note FreeType doesn't give too much info to build a proper font style.
1614   if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
1615   {
1616     description.slant = FontSlant::ITALIC;
1617   }
1618   if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
1619   {
1620     description.weight = FontWeight::BOLD;
1621   }
1622
1623   FontDescriptionId validatedFontId = 0u;
1624   if( !FindValidatedFont( description,
1625                           validatedFontId ) )
1626   {
1627     // Set the index to the vector of paths to font file names.
1628     validatedFontId = mFontDescriptionCache.size();
1629
1630     // Add the path to the cache.
1631     mFontDescriptionCache.push_back( description );
1632
1633     // Cache the index and the font's description.
1634     FontDescriptionCacheItem item( description,
1635                                    validatedFontId );
1636
1637     mValidatedFontCache.push_back( item );
1638
1639     // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
1640     mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
1641                                              requestedPointSize,
1642                                              id ) );
1643   }
1644 }
1645
1646 } // namespace Internal
1647
1648 } // namespace TextAbstraction
1649
1650 } // namespace Dali