Merge "Adaptor namespaces fixed." into new_text
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / font-client-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 "font-client-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <vector>
23 #include <ft2build.h>
24 #include FT_FREETYPE_H
25 #include FT_GLYPH_H
26 #include <fontconfig/fontconfig.h>
27 #include <dali/integration-api/debug.h>
28
29 // INTERNAL INCLUDES
30 #include <singleton-service-impl.h>
31
32 namespace Dali
33 {
34
35 namespace TextAbstraction
36 {
37
38 namespace Internal
39 {
40
41 struct FontClient::Plugin
42 {
43   struct CacheItem
44   {
45     CacheItem( FontId id, FT_Face ftFace, const std::string& path, PointSize26Dot6 pointSize, FaceIndex face, const FontMetrics& metrics )
46     : mFreeTypeFace( ftFace ),
47       mPath( path ),
48       mPointSize( pointSize ),
49       mFaceIndex( face ),
50       mMetrics( metrics )
51     {
52     }
53
54     FT_Face mFreeTypeFace;
55     std::string mPath;
56     PointSize26Dot6 mPointSize;
57     FaceIndex mFaceIndex;
58     FontMetrics mMetrics;
59   };
60
61   Plugin( unsigned int horizontalDpi, unsigned int verticalDpi )
62   : mFreeTypeLibrary( NULL ),
63     mDpiHorizontal( horizontalDpi ),
64     mDpiVertical( verticalDpi )
65   {
66   }
67
68   ~Plugin()
69   {
70     FT_Done_FreeType( mFreeTypeLibrary );
71   }
72
73   void Initialize()
74   {
75     int error = FT_Init_FreeType( &mFreeTypeLibrary );
76     if( FT_Err_Ok != error )
77     {
78       DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
79     }
80   }
81
82   void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
83   {
84     mDpiHorizontal = horizontalDpi;
85     mDpiVertical = verticalDpi;
86   }
87
88   void GetSystemFonts( FontList& systemFonts )
89   {
90     if( mSystemFonts.empty() )
91     {
92       InitSystemFonts();
93     }
94
95     systemFonts = mSystemFonts;
96   }
97
98   void InitSystemFonts()
99   {
100     FcFontSet* fontSet = GetFcFontSet();
101
102     if( fontSet )
103     {
104       mSystemFonts.reserve( fontSet->nfont );
105
106       for( int i = 0u; i < fontSet->nfont; ++i )
107       {
108         FcPattern* fontPattern = fontSet->fonts[i];
109
110         std::string path;
111
112         // Skip fonts with no path
113         if( GetFcString( fontPattern, FC_FILE, path ) )
114         {
115           mSystemFonts.push_back( FontDescription() );
116           FontDescription& fontDescription = mSystemFonts.back();
117
118           fontDescription.path = path;
119
120           GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
121           GetFcString( fontPattern, FC_STYLE, fontDescription.style );
122         }
123       }
124
125       FcFontSetDestroy( fontSet );
126     }
127   }
128
129   _FcFontSet* GetFcFontSet() const
130   {
131     // create a new pattern.
132     // a pattern holds a set of names, each name refers to a property of the font
133     FcPattern* pattern = FcPatternCreate();
134
135     // create an object set used to define which properties are to be returned in the patterns from FcFontList.
136     FcObjectSet* objectSet = FcObjectSetCreate();
137
138     // build an object set from a list of property names
139     FcObjectSetAdd( objectSet, FC_FILE );
140     FcObjectSetAdd( objectSet, FC_FAMILY );
141     FcObjectSetAdd( objectSet, FC_STYLE );
142
143     // get a list of fonts
144     // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
145     FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
146
147     // clear up the object set
148     if( objectSet )
149     {
150       FcObjectSetDestroy( objectSet );
151     }
152     // clear up the pattern
153     if( pattern )
154     {
155       FcPatternDestroy( pattern );
156     }
157
158     return fontset;
159   }
160
161   bool GetFcString( const FcPattern* pattern, const char* n, std::string& string )
162   {
163     FcChar8* file = NULL;
164     const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
165
166     if( FcResultMatch == retVal )
167     {
168       // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
169       string.assign( reinterpret_cast<const char*>( file ) );
170
171       return true;
172     }
173
174     return false;
175   }
176
177   bool FindSystemFont( Character charcode, FontDescription& systemFont )
178   {
179     // TODO - Use FcCharSetHasChar()
180
181     return false;
182   }
183
184   FontId GetFontId( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
185   {
186     FontId id( 0 );
187
188     if( NULL != mFreeTypeLibrary )
189     {
190       FontId foundId(0);
191       if( FindFont( path, pointSize, faceIndex, foundId ) )
192       {
193         id = foundId;
194       }
195       else
196       {
197         id = CreateFont( path, pointSize, faceIndex );
198       }
199     }
200
201     return id;
202   }
203
204   GlyphIndex GetGlyphIndex( FontId fontId, Character charcode )
205   {
206     GlyphIndex index( 0 );
207
208     if( fontId > 0 &&
209         fontId-1 < mFontCache.size() )
210     {
211       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
212
213       index = FT_Get_Char_Index( ftFace, charcode );
214     }
215
216     return index;
217   }
218
219   FontId CreateFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
220   {
221     FontId id( 0 );
222
223     // Create & cache new font face
224     FT_Face ftFace;
225     int error = FT_New_Face( mFreeTypeLibrary,
226                              path.c_str(),
227                              0,
228                              &ftFace );
229
230     if( FT_Err_Ok == error )
231     {
232       error = FT_Set_Char_Size( ftFace,
233                                 0,
234                                 pointSize,
235                                 mDpiHorizontal,
236                                 mDpiVertical );
237
238       if( FT_Err_Ok == error )
239       {
240         id = mFontCache.size() + 1;
241
242         FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
243         FontMetrics metrics( ftMetrics.ascender, ftMetrics.descender, ftMetrics.height );
244
245         mFontCache.push_back( CacheItem( id, ftFace, path, pointSize, faceIndex, metrics ) );
246       }
247       else
248       {
249         DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", pointSize );
250       }
251     }
252     else
253     {
254       DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
255     }
256
257     return id;
258   }
259
260   FontId FindDefaultFont( Character charcode )
261   {
262     // TODO - Return cached results based on script
263     return FontId(0);
264   }
265
266   void GetFontMetrics( FontId fontId, FontMetrics& metrics )
267   {
268     if( fontId > 0 &&
269         fontId-1 < mFontCache.size() )
270     {
271       metrics = mFontCache[fontId-1].mMetrics;
272     }
273     else
274     {
275       DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
276     }
277   }
278
279   bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
280   {
281     bool success( true );
282
283     for( unsigned int i=0; i<size; ++i )
284     {
285       FontId fontId = array[i].fontId;
286
287       if( fontId > 0 &&
288           fontId-1 < mFontCache.size() )
289       {
290         FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
291
292         int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
293
294         if( FT_Err_Ok == error )
295         {
296           array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
297           array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
298           if( horizontal )
299           {
300             array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
301             array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
302             array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
303           }
304           else
305           {
306             array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
307             array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
308             array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
309           }
310         }
311         else
312         {
313           success = false;
314         }
315       }
316       else
317       {
318         success = false;
319       }
320     }
321
322     return success;
323   }
324
325   BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
326   {
327     BitmapImage bitmap;
328
329     if( fontId > 0 &&
330         fontId-1 < mFontCache.size() )
331     {
332       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
333
334       FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
335       if( FT_Err_Ok == error )
336       {
337         FT_Glyph glyph;
338         error = FT_Get_Glyph( ftFace->glyph, &glyph );
339
340         // Convert to bitmap if necessary
341         if ( FT_Err_Ok == error )
342         {
343           if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
344           {
345             error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
346           }
347           else
348           {
349             DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
350           }
351         }
352         else
353         {
354           DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
355         }
356
357         if( FT_Err_Ok == error )
358         {
359           // Access the underlying bitmap data
360           FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
361           ConvertBitmap( bitmap, bitmapGlyph->bitmap );
362         }
363
364         // Created FT_Glyph object must be released with FT_Done_Glyph
365         FT_Done_Glyph( glyph );
366       }
367       else
368       {
369         DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
370       }
371     }
372
373     return bitmap;
374   }
375
376   void ConvertBitmap( BitmapImage& destBitmap, FT_Bitmap srcBitmap )
377   {
378     if( srcBitmap.width*srcBitmap.rows > 0 )
379     {
380       // TODO - Support all pixel modes
381       if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
382       {
383         if( srcBitmap.pitch == srcBitmap.width )
384         {
385           destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
386
387           PixelBuffer* destBuffer = destBitmap.GetBuffer();
388           memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
389         }
390       }
391     }
392   }
393
394 private:
395
396   bool FindFont( const std::string& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, FontId& found ) const
397   {
398     for( unsigned int i=0; i<mFontCache.size(); ++i )
399     {
400       if( mFontCache[i].mPointSize == pointSize &&
401           mFontCache[i].mPath == path &&
402           mFontCache[i].mFaceIndex == faceIndex )
403       {
404         found = i + 1;
405         return true;
406       }
407     }
408
409     return false;
410   }
411
412   FT_Library mFreeTypeLibrary;
413
414   FontList mSystemFonts;
415
416   std::vector<CacheItem> mFontCache;
417
418   unsigned int mDpiHorizontal;
419   unsigned int mDpiVertical;
420 };
421
422 FontClient::FontClient()
423 : mPlugin( NULL ),
424   mDpiHorizontal( 0 ),
425   mDpiVertical( 0 )
426 {
427 }
428
429 FontClient::~FontClient()
430 {
431   delete mPlugin;
432 }
433
434 Dali::TextAbstraction::FontClient FontClient::Get()
435 {
436   Dali::TextAbstraction::FontClient fontClientHandle;
437
438   Dali::SingletonService service( SingletonService::Get() );
439   if ( service )
440   {
441     // Check whether the singleton is already created
442     Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
443     if(handle)
444     {
445       // If so, downcast the handle
446       FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
447       fontClientHandle = Dali::TextAbstraction::FontClient( impl );
448     }
449     else // create and register the object
450     {
451       fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
452       service.Register( typeid( fontClientHandle ), fontClientHandle );
453     }
454   }
455
456   return fontClientHandle;
457 }
458
459 void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi  )
460 {
461   mDpiHorizontal = horizontalDpi;
462   mDpiVertical = verticalDpi;
463
464   // Allow DPI to be set without loading plugin
465   if( mPlugin )
466   {
467     mPlugin->SetDpi( horizontalDpi, verticalDpi  );
468   }
469 }
470
471 void FontClient::GetSystemFonts( FontList& systemFonts )
472 {
473   CreatePlugin();
474
475   mPlugin->GetSystemFonts( systemFonts );
476 }
477
478 bool FontClient::FindSystemFont( Character charcode, FontDescription& systemFont )
479 {
480   CreatePlugin();
481
482   return mPlugin->FindSystemFont( charcode, systemFont );
483 }
484
485 FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
486 {
487   CreatePlugin();
488
489   return mPlugin->GetFontId( path, pointSize, faceIndex );
490 }
491
492 FontId FontClient::FindDefaultFont( Character charcode )
493 {
494   CreatePlugin();
495
496   return mPlugin->FindDefaultFont( charcode );
497 }
498
499 void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
500 {
501   CreatePlugin();
502
503   return mPlugin->GetFontMetrics( fontId, metrics );
504 }
505
506 GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
507 {
508   CreatePlugin();
509
510   return mPlugin->GetGlyphIndex( fontId, charcode );
511 }
512
513 bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
514 {
515   CreatePlugin();
516
517   return mPlugin->GetGlyphMetrics( array, size, horizontal );
518 }
519
520 BitmapImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
521 {
522   CreatePlugin();
523
524   return mPlugin->CreateBitmap( fontId, glyphIndex );
525 }
526
527 void FontClient::CreatePlugin()
528 {
529   if( !mPlugin )
530   {
531     mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
532     mPlugin->Initialize();
533   }
534 }
535
536 } // namespace Internal
537
538 } // namespace FontClient
539
540 } // namespace Dali