Merge remote-tracking branch 'origin/tizen' into new_text
[platform/core/uifw/dali-adaptor.git] / text / dali / internal / text-abstraction / font-client-plugin-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/text-abstraction/font-client-plugin-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/common/vector-wrapper.h>
23 #include <dali/public-api/text-abstraction/glyph-info.h>
24 #include <dali/integration-api/debug.h>
25
26 /**
27  * Conversion from Fractional26.6 to float
28  */
29 namespace
30 {
31 const float FROM_266 = 1.0f / 64.0f;
32
33 const std::string FONT_FORMAT( "TrueType" );
34 const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
35 const std::string DEFAULT_FONT_STYLE( "Regular" );
36 }
37
38 namespace Dali
39 {
40
41 namespace TextAbstraction
42 {
43
44 namespace Internal
45 {
46
47 FontClient::Plugin::CacheItem::CacheItem( FontId id,
48                                           FT_Face ftFace,
49                                           const std::string& path,
50                                           PointSize26Dot6 pointSize,
51                                           FaceIndex face,
52                                           const FontMetrics& metrics )
53 : mFreeTypeFace( ftFace ),
54   mPath( path ),
55   mPointSize( pointSize ),
56   mFaceIndex( face ),
57   mMetrics( metrics )
58 {}
59
60 FontClient::Plugin::Plugin( unsigned int horizontalDpi,
61                             unsigned int verticalDpi )
62 : mFreeTypeLibrary( NULL ),
63   mDpiHorizontal( horizontalDpi ),
64   mDpiVertical( verticalDpi )
65 {}
66
67 FontClient::Plugin::~Plugin()
68 {
69   FT_Done_FreeType( mFreeTypeLibrary );
70 }
71
72 void FontClient::Plugin::Initialize()
73 {
74   int error = FT_Init_FreeType( &mFreeTypeLibrary );
75   if( FT_Err_Ok != error )
76   {
77     DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
78   }
79 }
80
81 void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
82                                  unsigned int verticalDpi )
83 {
84   mDpiHorizontal = horizontalDpi;
85   mDpiVertical = verticalDpi;
86 }
87
88 void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
89 {
90   if( mSystemFonts.empty() )
91   {
92     InitSystemFonts();
93   }
94
95   systemFonts = mSystemFonts;
96 }
97
98 void FontClient::Plugin::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* FontClient::Plugin::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 FontClient::Plugin::GetFcString( const FcPattern* pattern,
162                                       const char* n,
163                                       std::string& string )
164 {
165   FcChar8* file = NULL;
166   const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
167
168   if( FcResultMatch == retVal )
169   {
170     // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
171     string.assign( reinterpret_cast<const char*>( file ) );
172
173     return true;
174   }
175
176   return false;
177 }
178
179 void FontClient::Plugin::GetDescription( FontId id,
180                                          FontDescription& fontDescription ) const
181 {
182   // TODO
183 }
184
185 PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
186 {
187   return 12*64;
188 }
189
190 FontId FontClient::Plugin::FindDefaultFont( Character charcode,
191                                             PointSize26Dot6 pointSize )
192 {
193   // TODO - Use FcCharSetHasChar()
194   return FontId(0);
195 }
196
197 FontId FontClient::Plugin::GetFontId( const std::string& path,
198                                       PointSize26Dot6 pointSize,
199                                       FaceIndex faceIndex )
200 {
201   FontId id( 0 );
202
203   if( NULL != mFreeTypeLibrary )
204   {
205     FontId foundId(0);
206     if( FindFont( path, pointSize, faceIndex, foundId ) )
207     {
208       id = foundId;
209     }
210     else
211     {
212       id = CreateFont( path, pointSize, faceIndex );
213     }
214   }
215
216   return id;
217 }
218
219 FontId FontClient::Plugin::GetFontId( const FontFamily& fontFamily,
220                                       const FontStyle& fontStyle,
221                                       PointSize26Dot6 pointSize,
222                                       FaceIndex faceIndex )
223 {
224   return 0u;
225 }
226
227 GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
228                                               Character charcode )
229 {
230   GlyphIndex index( 0 );
231
232   if( fontId > 0 &&
233       fontId-1 < mFontCache.size() )
234   {
235     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
236
237     index = FT_Get_Char_Index( ftFace, charcode );
238   }
239
240   return index;
241 }
242
243 FontId FontClient::Plugin::CreateFont( const std::string& path,
244                                        PointSize26Dot6 pointSize,
245                                        FaceIndex faceIndex )
246 {
247   FontId id( 0 );
248
249   // Create & cache new font face
250   FT_Face ftFace;
251   int error = FT_New_Face( mFreeTypeLibrary,
252                            path.c_str(),
253                            0,
254                            &ftFace );
255
256   if( FT_Err_Ok == error )
257   {
258     error = FT_Set_Char_Size( ftFace,
259                               0,
260                               pointSize,
261                               mDpiHorizontal,
262                               mDpiVertical );
263
264     if( FT_Err_Ok == error )
265     {
266       id = mFontCache.size() + 1;
267
268       FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
269
270       FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
271                            static_cast< float >( ftMetrics.descender ) * FROM_266,
272                            static_cast< float >( ftMetrics.height    ) * FROM_266 );
273
274       mFontCache.push_back( CacheItem( id, ftFace, path, pointSize, faceIndex, metrics ) );
275     }
276     else
277     {
278       DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", pointSize );
279     }
280   }
281   else
282   {
283     DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
284   }
285
286   return id;
287 }
288
289 void FontClient::Plugin::GetFontMetrics( FontId fontId,
290                                          FontMetrics& metrics )
291 {
292   if( fontId > 0 &&
293       fontId-1 < mFontCache.size() )
294   {
295     metrics = mFontCache[fontId-1].mMetrics;
296   }
297   else
298   {
299     DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
300   }
301 }
302
303 bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
304                                           uint32_t size,
305                                           bool horizontal )
306 {
307   bool success( true );
308
309   for( unsigned int i=0; i<size; ++i )
310   {
311     FontId fontId = array[i].fontId;
312
313     if( fontId > 0 &&
314         fontId-1 < mFontCache.size() )
315     {
316       FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
317
318       int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
319
320       if( FT_Err_Ok == error )
321       {
322         array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
323         array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
324         if( horizontal )
325         {
326           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
327           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
328           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
329         }
330         else
331         {
332           array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
333           array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
334           array[i].advance  = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
335         }
336       }
337       else
338       {
339         success = false;
340       }
341     }
342     else
343     {
344       success = false;
345     }
346   }
347
348   return success;
349 }
350
351 BitmapImage FontClient::Plugin::CreateBitmap( FontId fontId,
352                                               GlyphIndex glyphIndex )
353 {
354   BitmapImage bitmap;
355
356   if( fontId > 0 &&
357       fontId-1 < mFontCache.size() )
358   {
359     FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
360
361     FT_Error error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
362     if( FT_Err_Ok == error )
363     {
364       FT_Glyph glyph;
365       error = FT_Get_Glyph( ftFace->glyph, &glyph );
366
367       // Convert to bitmap if necessary
368       if ( FT_Err_Ok == error )
369       {
370         if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
371         {
372           error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
373         }
374         else
375         {
376           DALI_LOG_ERROR( "FT_Glyph_To_Bitmap Failed with error: %d\n", error );
377         }
378       }
379       else
380       {
381         DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
382       }
383
384       if( FT_Err_Ok == error )
385       {
386         // Access the underlying bitmap data
387         FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
388         ConvertBitmap( bitmap, bitmapGlyph->bitmap );
389       }
390
391       // Created FT_Glyph object must be released with FT_Done_Glyph
392       FT_Done_Glyph( glyph );
393     }
394     else
395     {
396       DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
397     }
398   }
399
400   return bitmap;
401 }
402
403 void FontClient::Plugin::ConvertBitmap( BitmapImage& destBitmap,
404                                         FT_Bitmap srcBitmap )
405 {
406   if( srcBitmap.width*srcBitmap.rows > 0 )
407   {
408     // TODO - Support all pixel modes
409     if( FT_PIXEL_MODE_GRAY == srcBitmap.pixel_mode )
410     {
411       if( srcBitmap.pitch == srcBitmap.width )
412       {
413         destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
414
415         PixelBuffer* destBuffer = destBitmap.GetBuffer();
416         memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
417       }
418     }
419   }
420 }
421
422 bool FontClient::Plugin::FindFont( const std::string& path,
423                                    PointSize26Dot6 pointSize,
424                                    FaceIndex faceIndex,
425                                    FontId& found ) const
426 {
427   for( unsigned int i=0; i<mFontCache.size(); ++i )
428   {
429     if( mFontCache[i].mPointSize == pointSize &&
430         mFontCache[i].mPath == path &&
431         mFontCache[i].mFaceIndex == faceIndex )
432     {
433       found = i + 1;
434       return true;
435     }
436   }
437
438   return false;
439 }
440
441 } // namespace Internal
442
443 } // namespace TextAbstraction
444
445 } // namespace Dali