1 /*
2    (c) Copyright 2001-2010  The world wide DirectFB Open Source Community (directfb.org)
3    (c) Copyright 2000-2004  Convergence (integrated media) GmbH
4 
5    All rights reserved.
6 
7    Written by Denis Oliver Kropp <dok@directfb.org>,
8               Andreas Hundt <andi@fischlustig.de>,
9               Sven Neumann <neo@directfb.org>,
10               Ville Syrjälä <syrjala@sci.fi> and
11               Claudio Ciccani <klan@users.sf.net>.
12 
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2 of the License, or (at your option) any later version.
17 
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22 
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the
25    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26    Boston, MA 02111-1307, USA.
27 */
28 
29 #include <config.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <stdarg.h>
35 #include <math.h>
36 
37 #include <directfb.h>
38 
39 #include <core/fonts.h>
40 #include <core/gfxcard.h>
41 
42 #include <core/CoreSurface.h>
43 
44 #include <gfx/convert.h>
45 
46 #include <media/idirectfbfont.h>
47 
48 #include <direct/mem.h>
49 #include <direct/memcpy.h>
50 #include <direct/messages.h>
51 #include <direct/utf8.h>
52 #include <direct/util.h>
53 
54 #include <misc/conf.h>
55 #include <misc/util.h>
56 
57 #undef SIZEOF_LONG
58 #include <ft2build.h>
59 #include FT_GLYPH_H
60 
61 #ifndef FT_LOAD_TARGET_MONO
62     /* FT_LOAD_TARGET_MONO was added in FreeType-2.1.3. We have to use
63        (less good) FT_LOAD_MONOCHROME with older versions. Make it an
64        alias for code simplicity. */
65     #define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
66 #endif
67 
68 #ifndef FT_LOAD_FORCE_AUTOHINT
69     #define FT_LOAD_FORCE_AUTOHINT 0
70 #endif
71 #ifndef FT_LOAD_TARGET_LIGHT
72     #define FT_LOAD_TARGET_LIGHT 0
73 #endif
74 
75 static DFBResult
76 Probe( IDirectFBFont_ProbeContext *ctx );
77 
78 static DFBResult
79 Construct( IDirectFBFont               *thiz,
80            CoreDFB                     *core,
81            IDirectFBFont_ProbeContext  *ctx,
82            DFBFontDescription          *desc );
83 
84 #include <direct/interface_implementation.h>
85 
86 DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBFont, FT2 )
87 
88 static FT_Library      library           = NULL;
89 static int             library_ref_count = 0;
90 static pthread_mutex_t library_mutex     = PTHREAD_MUTEX_INITIALIZER;
91 
92 #define KERNING_CACHE_MIN    0
93 #define KERNING_CACHE_MAX  127
94 #define KERNING_CACHE_SIZE (KERNING_CACHE_MAX - KERNING_CACHE_MIN + 1)
95 
96 #define KERNING_DO_CACHE(a,b)      ((a) >= KERNING_CACHE_MIN && \
97                                     (a) <= KERNING_CACHE_MAX && \
98                                     (b) >= KERNING_CACHE_MIN && \
99                                     (b) <= KERNING_CACHE_MAX)
100 
101 #define KERNING_CACHE_ENTRY(a,b)   \
102      (data->kerning[(a)-KERNING_CACHE_MIN][(b)-KERNING_CACHE_MIN])
103 
104 #define CHAR_INDEX(c)    (((c) < 256) ? data->indices[c] : FT_Get_Char_Index( data->face, c ))
105 
106 typedef struct {
107      FT_Face      face;
108      int          disable_charmap;
109      int          fixed_advance;
110      bool         fixed_clip;
111      unsigned int indices[256];
112 } FT2ImplData;
113 
114 typedef struct {
115      signed char x;
116      signed char y;
117 } KerningCacheEntry;
118 
119 typedef struct {
120      FT2ImplData base;
121 
122      KerningCacheEntry kerning[KERNING_CACHE_SIZE][KERNING_CACHE_SIZE];
123 } FT2ImplKerningData;
124 
125 /**********************************************************************************************************************/
126 
127 static DFBResult
ft2UTF8GetCharacterIndex(CoreFont * thiz,unsigned int character,unsigned int * ret_index)128 ft2UTF8GetCharacterIndex( CoreFont     *thiz,
129                           unsigned int  character,
130                           unsigned int *ret_index )
131 {
132      FT2ImplData *data = thiz->impl_data;
133 
134      D_MAGIC_ASSERT( thiz, CoreFont );
135 
136      if (data->disable_charmap)
137           *ret_index = character;
138      else {
139           pthread_mutex_lock ( &library_mutex );
140 
141           *ret_index = CHAR_INDEX( character );
142 
143           pthread_mutex_unlock ( &library_mutex );
144      }
145 
146      return DFB_OK;
147 }
148 
149 static DFBResult
ft2UTF8DecodeText(CoreFont * thiz,const void * text,int length,unsigned int * ret_indices,int * ret_num)150 ft2UTF8DecodeText( CoreFont       *thiz,
151                    const void     *text,
152                    int             length,
153                    unsigned int   *ret_indices,
154                    int            *ret_num )
155 {
156      int pos = 0, num = 0;
157      const u8 *bytes   = text;
158      FT2ImplData *data = thiz->impl_data;
159 
160      D_MAGIC_ASSERT( thiz, CoreFont );
161      D_ASSERT( text != NULL );
162      D_ASSERT( length >= 0 );
163      D_ASSERT( ret_indices != NULL );
164      D_ASSERT( ret_num != NULL );
165 
166      pthread_mutex_lock ( &library_mutex );
167 
168      while (pos < length) {
169           unsigned int c;
170 
171           if (bytes[pos] < 128)
172                c = bytes[pos++];
173           else {
174                c = DIRECT_UTF8_GET_CHAR( &bytes[pos] );
175                pos += DIRECT_UTF8_SKIP(bytes[pos]);
176           }
177 
178           if (data->disable_charmap)
179                ret_indices[num++] = c;
180           else
181                ret_indices[num++] = CHAR_INDEX( c );
182      }
183 
184      pthread_mutex_unlock ( &library_mutex );
185 
186      *ret_num = num;
187 
188      return DFB_OK;
189 }
190 
191 static const CoreFontEncodingFuncs ft2UTF8Funcs = {
192      .GetCharacterIndex = ft2UTF8GetCharacterIndex,
193      .DecodeText        = ft2UTF8DecodeText,
194 };
195 
196 /**********************************************************************************************************************/
197 
198 static DFBResult
ft2Latin1GetCharacterIndex(CoreFont * thiz,unsigned int character,unsigned int * ret_index)199 ft2Latin1GetCharacterIndex( CoreFont     *thiz,
200                             unsigned int  character,
201                             unsigned int *ret_index )
202 {
203      FT2ImplData *data = thiz->impl_data;
204 
205      D_MAGIC_ASSERT( thiz, CoreFont );
206 
207      if (data->disable_charmap)
208           *ret_index = character;
209      else
210           *ret_index = data->indices[character];
211 
212      return DFB_OK;
213 }
214 
215 static DFBResult
ft2Latin1DecodeText(CoreFont * thiz,const void * text,int length,unsigned int * ret_indices,int * ret_num)216 ft2Latin1DecodeText( CoreFont       *thiz,
217                      const void     *text,
218                      int             length,
219                      unsigned int   *ret_indices,
220                      int            *ret_num )
221 {
222      int i;
223      const u8 *bytes   = text;
224      FT2ImplData *data = thiz->impl_data;
225 
226      D_MAGIC_ASSERT( thiz, CoreFont );
227      D_ASSERT( text != NULL );
228      D_ASSERT( length >= 0 );
229      D_ASSERT( ret_indices != NULL );
230      D_ASSERT( ret_num != NULL );
231 
232      if (data->disable_charmap) {
233           for (i=0; i<length; i++)
234                ret_indices[i] = bytes[i];
235      }
236      else {
237           for (i=0; i<length; i++)
238                ret_indices[i] = data->indices[bytes[i]];
239      }
240 
241      *ret_num = length;
242 
243      return DFB_OK;
244 }
245 
246 static const CoreFontEncodingFuncs ft2Latin1Funcs = {
247      .GetCharacterIndex = ft2Latin1GetCharacterIndex,
248      .DecodeText        = ft2Latin1DecodeText,
249 };
250 
251 /**********************************************************************************************************************/
252 
253 static DFBResult
render_glyph(CoreFont * thiz,unsigned int index,CoreGlyphData * info)254 render_glyph( CoreFont      *thiz,
255               unsigned int   index,
256               CoreGlyphData *info )
257 {
258      FT_Error     err;
259      FT_Face      face;
260      FT_Int       load_flags;
261      u8          *src;
262      int          y;
263      FT2ImplData *data    = thiz->impl_data;
264      CoreSurface *surface = info->surface;
265      CoreSurfaceBufferLock  lock;
266 
267      pthread_mutex_lock ( &library_mutex );
268 
269      face = data->face;
270 
271      load_flags = (unsigned long) face->generic.data;
272      load_flags |= FT_LOAD_RENDER;
273 
274      if ((err = FT_Load_Glyph( face, index, load_flags ))) {
275           D_DEBUG( "DirectFB/FontFT2: Could not render glyph for character index #%d!\n", index );
276           pthread_mutex_unlock ( &library_mutex );
277           return DFB_FAILURE;
278      }
279 
280      pthread_mutex_unlock ( &library_mutex );
281 
282      err = dfb_surface_lock_buffer( surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock );
283      if (err) {
284           D_DERROR( err, "DirectFB/FontFT2: Unable to lock surface!\n" );
285           return err;
286      }
287 
288      info->width = face->glyph->bitmap.width;
289      if (info->width + info->start > surface->config.size.w)
290           info->width = surface->config.size.w - info->start;
291 
292      info->height = face->glyph->bitmap.rows;
293      if (info->height > surface->config.size.h)
294           info->height = surface->config.size.h;
295 
296      /* bitmap_left and bitmap_top are relative to the glyph's origin on the
297         baseline.  info->left and info->top are relative to the top-left of the
298         character cell. */
299      info->left =   face->glyph->bitmap_left - thiz->ascender*thiz->up_unit_x;
300      info->top  = - face->glyph->bitmap_top  - thiz->ascender*thiz->up_unit_y;
301 
302      if (data->fixed_clip) {
303           while (info->left + info->width > data->fixed_advance)
304                info->left--;
305 
306           if (info->left < 0)
307                info->left = 0;
308 
309           if (info->width > data->fixed_advance)
310                info->width = data->fixed_advance;
311      }
312 
313      src = face->glyph->bitmap.buffer;
314      lock.addr += DFB_BYTES_PER_LINE(surface->config.format, info->start);
315 
316      for (y=0; y < info->height; y++) {
317           int  i, j, n;
318           u8  *dst8  = lock.addr;
319           u16 *dst16 = lock.addr;
320           u32 *dst32 = lock.addr;
321 
322           switch (face->glyph->bitmap.pixel_mode) {
323                case ft_pixel_mode_grays:
324                     switch (surface->config.format) {
325                          case DSPF_ARGB:
326                               if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
327                                    for (i=0; i<info->width; i++)
328                                         dst32[i] = src[i] * 0x01010101;
329                               }
330                               else
331                                    for (i=0; i<info->width; i++)
332                                         dst32[i] = (src[i] << 24) | 0xFFFFFF;
333                               break;
334                          case DSPF_AiRGB:
335                               for (i=0; i<info->width; i++)
336                                    dst32[i] = ((src[i] ^ 0xFF) << 24) | 0xFFFFFF;
337                               break;
338                          case DSPF_ARGB8565:
339                               for (i = 0, j = -1; i < info->width; ++i) {
340                                   u32 d;
341                                   if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
342                                        d = src[i] * 0x01010101;
343                                        d = ARGB_TO_ARGB8565 (d);
344                                   }
345                                   else
346                                        d = (src[i] << 16) | 0xFFFF;
347 #ifdef WORDS_BIGENDIAN
348                                    dst8[++j] = (d >> 16) & 0xff;
349                                    dst8[++j] = (d >>  8) & 0xff;
350                                    dst8[++j] = (d >>  0) & 0xff;
351 #else
352                                    dst8[++j] = (d >>  0) & 0xff;
353                                    dst8[++j] = (d >>  8) & 0xff;
354                                    dst8[++j] = (d >> 16) & 0xff;
355 #endif
356                               }
357                               break;
358                          case DSPF_ARGB4444:
359                          case DSPF_RGBA4444:
360                               if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
361                                    for (i=0; i<info->width; i++)
362                                         dst16[i] = (src[i] >> 4) * 0x1111;
363                               }
364                               else {
365                                    if( surface->config.format == DSPF_ARGB4444 ) {
366                                         for (i=0; i<info->width; i++)
367                                              dst16[i] = (src[i] << 8) | 0x0FFF;
368                                    } else {
369                                         for (i=0; i<info->width; i++)
370                                              dst16[i] = (src[i] >> 4) | 0xFFF0;
371                                    }
372                               }
373                               break;
374                          case DSPF_ARGB2554:
375                               for (i=0; i<info->width; i++)
376                                    dst16[i] = (src[i] << 8) | 0x3FFF;
377                               break;
378                          case DSPF_ARGB1555:
379                               if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
380                                    for (i=0; i<info->width; i++) {
381                                         unsigned short x = src[i] >> 3;
382                                         dst16[i] = ((src[i] & 0x80) << 8) |
383                                              (x << 10) | (x << 5) | x;
384                                    }
385                               }
386                               else {
387                                    for (i=0; i<info->width; i++)
388                                         dst16[i] = (src[i] << 8) | 0x7FFF;
389                               }
390                               break;
391                          case DSPF_RGBA5551:
392                               if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
393                                    for (i=0; i<info->width; i++) {
394                                         unsigned short x = src[i] >> 3;
395                                         dst16[i] =  (x << 11) | (x << 6) | (x << 1) |
396                                              (src[i] >> 7);
397                                    }
398                               }
399                               else {
400                                    for (i=0; i<info->width; i++)
401                                         dst16[i] = 0xFFFE | (src[i] >> 7);
402                               }
403                               break;
404                          case DSPF_A8:
405                               direct_memcpy( lock.addr, src, info->width );
406                               break;
407                          case DSPF_A4:
408                               for (i=0, j=0; i<info->width; i+=2, j++)
409                                    dst8[j] = (src[i] & 0xF0) | (src[i+1] >> 4);
410                               break;
411                          case DSPF_A1:
412                               for (i=0, j=0; i < info->width; ++j) {
413                                    register u8 p = 0;
414 
415                                    for (n=0; n<8 && i<info->width; ++i, ++n)
416                                         p |= (src[i] & 0x80) >> n;
417 
418                                    dst8[j] = p;
419                               }
420                               break;
421                          case DSPF_A1_LSB:
422                               for (i=0, j=0; i < info->width; ++j) {
423                                    register u8 p = 0;
424 
425                                    for (n=0; n<8 && i<info->width; ++i, ++n)
426                                         p |= (src[i] & 0x80) >> (7-n);
427 
428                                    dst8[j] = p;
429                               }
430                               break;
431                          case DSPF_LUT2:
432                               for (i=0, j=0; i < info->width; ++j) {
433                                    register u8 p = 0;
434 
435                                    for (n=0; n<8 && i<info->width; ++i, n+=2)
436                                         p |= (src[i] & 0xC0) >> n;
437 
438                                    dst8[j] = p;
439                               }
440                               break;
441                          default:
442                               D_UNIMPLEMENTED();
443                               break;
444                     }
445                     break;
446 
447                case ft_pixel_mode_mono:
448                     switch (surface->config.format) {
449                          case DSPF_ARGB:
450                               for (i=0; i<info->width; i++)
451                                    dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
452                                                 0xFF : 0x00) << 24) | 0xFFFFFF;
453                               break;
454                          case DSPF_AiRGB:
455                               for (i=0; i<info->width; i++)
456                                    dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
457                                                 0x00 : 0xFF) << 24) | 0xFFFFFF;
458                               break;
459                          case DSPF_ARGB8565:
460                               for (i = 0, j = -1; i < info->width; ++i) {
461                                    u32 d;
462                                    if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) {
463                                         d = ((src[i>>3] & (1<<(7-(i%8)))) ?
464                                              0xffffff : 0x000000);
465                                    }
466                                    else
467                                        d = (((src[i>>3] & (1<<(7-(i%8)))) ?
468                                              0xff : 0x00) << 16) | 0xffff;
469 #ifdef WORDS_BIGENDIAN
470                                    dst8[++j] = (d >> 16) & 0xff;
471                                    dst8[++j] = (d >>  8) & 0xff;
472                                    dst8[++j] = (d >>  0) & 0xff;
473 #else
474                                    dst8[++j] = (d >>  0) & 0xff;
475                                    dst8[++j] = (d >>  8) & 0xff;
476                                    dst8[++j] = (d >> 16) & 0xff;
477 #endif
478                               }
479                               break;
480                          case DSPF_ARGB4444:
481                               for (i=0; i<info->width; i++)
482                                    dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
483                                                 0xF : 0x0) << 12) | 0xFFF;
484                               break;
485                          case DSPF_RGBA4444:
486                               for (i=0; i<info->width; i++)
487                                    dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
488                                                 0xF : 0x0)      ) | 0xFFF0;
489                               break;
490                          case DSPF_ARGB2554:
491                               for (i=0; i<info->width; i++)
492                                    dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
493                                                 0x3 : 0x0) << 14) | 0x3FFF;
494                               break;
495                          case DSPF_ARGB1555:
496                               for (i=0; i<info->width; i++)
497                                    dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ?
498                                                 0x1 : 0x0) << 15) | 0x7FFF;
499                               break;
500                          case DSPF_RGBA5551:
501                               for (i=0; i<info->width; i++)
502                                    dst16[i] = 0xFFFE | (((src[i>>3] & (1<<(7-(i%8)))) ?
503                                                 0x1 : 0x0));
504                               break;
505                          case DSPF_A8:
506                               for (i=0; i<info->width; i++)
507                                    dst8[i] = (src[i>>3] &
508                                               (1<<(7-(i%8)))) ? 0xFF : 0x00;
509                               break;
510                          case DSPF_A4:
511                               for (i=0, j=0; i<info->width; i+=2, j++)
512                                    dst8[j] = ((src[i>>3] &
513                                               (1<<(7-(i%8)))) ? 0xF0 : 0x00) |
514                                              ((src[(i+1)>>3] &
515                                               (1<<(7-((i+1)%8)))) ? 0x0F : 0x00);
516                               break;
517                          case DSPF_A1:
518                               direct_memcpy( lock.addr, src, DFB_BYTES_PER_LINE(DSPF_A1, info->width) );
519                               break;
520                          case DSPF_A1_LSB:
521                               for (i=0, j=0; i < info->width; ++j) {
522                                    register u8 p = 0;
523 
524                                    for (n=0; n<8 && i<info->width; ++i, ++n)
525                                         p |= (((src[i] >> n) & 1) << (7-n));
526 
527                                    dst8[j] = p;
528                               }
529                               break;
530                          default:
531                               D_UNIMPLEMENTED();
532                               break;
533                     }
534                     break;
535 
536                default:
537                     break;
538 
539           }
540 
541           src += face->glyph->bitmap.pitch;
542 
543           lock.addr += lock.pitch;
544      }
545 
546      dfb_surface_unlock_buffer( surface, &lock );
547 
548      return DFB_OK;
549 }
550 
551 
552 static DFBResult
get_glyph_info(CoreFont * thiz,unsigned int index,CoreGlyphData * info)553 get_glyph_info( CoreFont      *thiz,
554                 unsigned int   index,
555                 CoreGlyphData *info )
556 {
557      FT_Error err;
558      FT_Face  face;
559      FT_Int   load_flags;
560      FT2ImplData *data = (FT2ImplData*) thiz->impl_data;
561 
562      pthread_mutex_lock ( &library_mutex );
563 
564      face = data->face;
565 
566      load_flags = (unsigned long) face->generic.data;
567 
568      if ((err = FT_Load_Glyph( face, index, load_flags ))) {
569           D_DEBUG( "DirectFB/FontFT2: Could not load glyph for character index #%d!\n", index );
570 
571           pthread_mutex_unlock ( &library_mutex );
572 
573           return DFB_FAILURE;
574      }
575 
576      if (face->glyph->format != ft_glyph_format_bitmap) {
577           err = FT_Render_Glyph( face->glyph,
578                                  (load_flags & FT_LOAD_TARGET_MONO) ? ft_render_mode_mono : ft_render_mode_normal );
579           if (err) {
580                D_ERROR( "DirectFB/FontFT2: Could not render glyph for character index #%d!\n", index );
581 
582                pthread_mutex_unlock ( &library_mutex );
583 
584                return DFB_FAILURE;
585           }
586      }
587 
588      pthread_mutex_unlock ( &library_mutex );
589 
590      info->width   = face->glyph->bitmap.width;
591      info->height  = face->glyph->bitmap.rows;
592 
593      if (data->fixed_advance) {
594           info->xadvance = - data->fixed_advance * thiz->up_unit_y;
595           info->yadvance =   data->fixed_advance * thiz->up_unit_x;
596      }
597      else {
598           info->xadvance =   face->glyph->advance.x >> 6;
599           info->yadvance = - face->glyph->advance.y >> 6;
600      }
601 
602      if (data->fixed_clip && info->width > data->fixed_advance)
603           info->width = data->fixed_advance;
604 
605      return DFB_OK;
606 }
607 
608 
609 static DFBResult
get_kerning(CoreFont * thiz,unsigned int prev,unsigned int current,int * kern_x,int * kern_y)610 get_kerning( CoreFont     *thiz,
611              unsigned int  prev,
612              unsigned int  current,
613              int          *kern_x,
614              int          *kern_y)
615 {
616      FT_Vector vector;
617 
618      FT2ImplKerningData *data = thiz->impl_data;
619      KerningCacheEntry *cache = NULL;
620 
621      D_ASSUME( (kern_x != NULL) || (kern_y != NULL) );
622 
623      /*
624       * Use cached values if characters are in the
625       * cachable range and the cache entry is already filled.
626       */
627      if (KERNING_DO_CACHE (prev, current)) {
628           cache = &KERNING_CACHE_ENTRY (prev, current);
629 
630           if (kern_x)
631                *kern_x = (int) cache->x;
632 
633           if (kern_y)
634                *kern_y = (int) cache->y;
635 
636           return DFB_OK;
637      }
638 
639      pthread_mutex_lock ( &library_mutex );
640 
641      /* Lookup kerning values for the character pair. */
642      /* The vector returned by FreeType does not allow for any rotation. */
643      FT_Get_Kerning( data->base.face,
644                      prev, current, ft_kerning_default, &vector );
645 
646      pthread_mutex_unlock ( &library_mutex );
647 
648      /* Convert to integer. */
649      if (kern_x)
650           *kern_x = (int)(- vector.x*thiz->up_unit_y + vector.y*thiz->up_unit_x) >> 6;
651 
652      if (kern_y)
653           *kern_y = (int)(  vector.y*thiz->up_unit_y + vector.x*thiz->up_unit_x) >> 6;
654 
655      return DFB_OK;
656 }
657 
658 static void
init_kerning_cache(FT2ImplKerningData * data,float up_unit_x,float up_unit_y)659 init_kerning_cache( FT2ImplKerningData *data, float up_unit_x, float up_unit_y )
660 {
661      int a, b;
662 
663      pthread_mutex_lock ( &library_mutex );
664 
665      for (a=KERNING_CACHE_MIN; a<=KERNING_CACHE_MAX; a++) {
666           for (b=KERNING_CACHE_MIN; b<=KERNING_CACHE_MAX; b++) {
667                FT_Vector          vector;
668                KerningCacheEntry *cache = &KERNING_CACHE_ENTRY( a, b );
669 
670                /* Lookup kerning values for the character pair. */
671                FT_Get_Kerning( data->base.face,
672                                a, b, ft_kerning_default, &vector );
673 
674                cache->x = (signed char) ((int)(- vector.x*up_unit_y + vector.y*up_unit_x) >> 6);
675                cache->y = (signed char) ((int)(  vector.y*up_unit_y + vector.x*up_unit_x) >> 6);
676           }
677      }
678 
679      pthread_mutex_unlock ( &library_mutex );
680 }
681 
682 static DFBResult
init_freetype(void)683 init_freetype( void )
684 {
685      FT_Error err;
686 
687      pthread_mutex_lock ( &library_mutex );
688 
689      if (!library) {
690           D_DEBUG( "DirectFB/FontFT2: Initializing the FreeType2 library.\n" );
691           err = FT_Init_FreeType( &library );
692           if (err) {
693                D_ERROR( "DirectFB/FontFT2: "
694                          "Initialization of the FreeType2 library failed!\n" );
695                library = NULL;
696                pthread_mutex_unlock( &library_mutex );
697                return DFB_FAILURE;
698           }
699      }
700 
701      library_ref_count++;
702      pthread_mutex_unlock( &library_mutex );
703 
704      return DFB_OK;
705 }
706 
707 
708 static void
release_freetype(void)709 release_freetype( void )
710 {
711      pthread_mutex_lock( &library_mutex );
712 
713      if (library && --library_ref_count == 0) {
714           D_DEBUG( "DirectFB/FontFT2: Releasing the FreeType2 library.\n" );
715           FT_Done_FreeType( library );
716           library = NULL;
717      }
718 
719      pthread_mutex_unlock( &library_mutex );
720 }
721 
722 
723 static void
IDirectFBFont_FT2_Destruct(IDirectFBFont * thiz)724 IDirectFBFont_FT2_Destruct( IDirectFBFont *thiz )
725 {
726      IDirectFBFont_data *data = (IDirectFBFont_data*)thiz->priv;
727 
728      if (data->font->impl_data) {
729           FT2ImplData *impl_data = (FT2ImplData*) data->font->impl_data;
730 
731           pthread_mutex_lock ( &library_mutex );
732           FT_Done_Face( impl_data->face );
733           pthread_mutex_unlock ( &library_mutex );
734 
735           D_FREE( impl_data );
736 
737           data->font->impl_data = NULL;
738      }
739 
740      IDirectFBFont_Destruct( thiz );
741 
742      release_freetype();
743 }
744 
745 
746 static DirectResult
IDirectFBFont_FT2_Release(IDirectFBFont * thiz)747 IDirectFBFont_FT2_Release( IDirectFBFont *thiz )
748 {
749      DIRECT_INTERFACE_GET_DATA(IDirectFBFont)
750 
751      if (--data->ref == 0) {
752           IDirectFBFont_FT2_Destruct( thiz );
753      }
754 
755      return DR_OK;
756 }
757 
758 
759 static DFBResult
Probe(IDirectFBFont_ProbeContext * ctx)760 Probe( IDirectFBFont_ProbeContext *ctx )
761 {
762      FT_Error err;
763      FT_Face  face;
764 
765      D_DEBUG( "DirectFB/FontFT2: Probe font `%s'.\n", ctx->filename );
766 
767      if(!ctx->content)
768           return DFB_UNSUPPORTED;
769 
770      if (init_freetype() != DFB_OK) {
771           return DFB_FAILURE;
772      }
773 
774      pthread_mutex_lock ( &library_mutex );
775 
776      /*
777       * This should be
778       * err = FT_New...Face( library, ctx->filename, -1, NULL );
779       * but due to freetype bugs it doesn't work.
780       */
781      err = FT_New_Memory_Face( library, ctx->content, ctx->content_size, 0, &face );
782      if (!err)
783           FT_Done_Face( face );
784      pthread_mutex_unlock ( &library_mutex );
785 
786      release_freetype();
787 
788      return err ? DFB_UNSUPPORTED : DFB_OK;
789 }
790 
791 
792 static DFBResult
Construct(IDirectFBFont * thiz,CoreDFB * core,IDirectFBFont_ProbeContext * ctx,DFBFontDescription * desc)793 Construct( IDirectFBFont               *thiz,
794            CoreDFB                     *core,
795            IDirectFBFont_ProbeContext  *ctx,
796            DFBFontDescription          *desc )
797 {
798      int                 i;
799      DFBResult           ret;
800      CoreFont           *font;
801      FT_Face             face;
802      FT_Error            err;
803      FT_Int              load_flags = FT_LOAD_DEFAULT;
804      FT2ImplData        *data;
805      bool                disable_charmap = false;
806      bool                disable_kerning = false;
807      bool                load_mono = false;
808      u32                 mask = 0;
809      const char         *filename = ctx->filename; /* intended for printf only */
810 
811      float sin_rot = 0.0;
812      float cos_rot = 1.0;
813 
814      D_DEBUG( "DirectFB/FontFT2: "
815               "Construct font from file `%s' (index %d) at pixel size %d x %d and rotation %d.\n",
816               filename,
817               (desc->flags & DFDESC_INDEX)    ? desc->index    : 0,
818               (desc->flags & DFDESC_WIDTH)    ? desc->width    : 0,
819               (desc->flags & DFDESC_HEIGHT)   ? desc->height   : 0,
820               (desc->flags & DFDESC_ROTATION) ? desc->rotation : 0 );
821 
822      if (init_freetype() != DFB_OK) {
823           DIRECT_DEALLOCATE_INTERFACE( thiz );
824           return DFB_FAILURE;
825      }
826 
827      pthread_mutex_lock ( &library_mutex );
828      err = FT_New_Memory_Face( library, ctx->content, ctx->content_size,
829                                (desc->flags & DFDESC_INDEX) ? desc->index : 0,
830                                &face );
831      pthread_mutex_unlock ( &library_mutex );
832      if (err) {
833           switch (err) {
834                case FT_Err_Unknown_File_Format:
835                     D_ERROR( "DirectFB/FontFT2: "
836                               "Unsupported font format in file `%s'!\n", filename );
837                     break;
838                default:
839                     D_ERROR( "DirectFB/FontFT2: "
840                               "Failed loading face %d from font file `%s'!\n",
841                               (desc->flags & DFDESC_INDEX) ? desc->index : 0,
842                               filename );
843                     break;
844           }
845           DIRECT_DEALLOCATE_INTERFACE( thiz );
846           return DFB_FAILURE;
847      }
848 
849      if ((desc->flags & DFDESC_ROTATION) && desc->rotation) {
850           if (!FT_IS_SCALABLE(face)) {
851                D_ERROR( "DirectFB/FontFT2: "
852                          "Face %d from font file `%s' is not scalable so cannot be rotated\n",
853                          (desc->flags & DFDESC_INDEX) ? desc->index : 0,
854                          filename );
855                pthread_mutex_lock ( &library_mutex );
856                FT_Done_Face( face );
857                pthread_mutex_unlock ( &library_mutex );
858                DIRECT_DEALLOCATE_INTERFACE( thiz );
859                return DFB_UNSUPPORTED;
860           }
861 
862           float rot_radians = 2.0 * M_PI * desc->rotation / (1<<24);
863           sin_rot = sin(rot_radians);
864           cos_rot = cos(rot_radians);
865 
866           int sin_rot_fx = (int)(sin_rot*65536.0);
867           int cos_rot_fx = (int)(cos_rot*65536.0);
868           FT_Matrix matrix;
869           matrix.xx =  cos_rot_fx;
870           matrix.xy = -sin_rot_fx;
871           matrix.yx =  sin_rot_fx;
872           matrix.yy =  cos_rot_fx;
873 
874           pthread_mutex_lock ( &library_mutex );
875           FT_Set_Transform( face, &matrix, NULL );
876           /* FreeType docs suggest FT_Set_Transform returns an error code, but it seems
877              that this is not the case. */
878           pthread_mutex_unlock ( &library_mutex );
879      }
880 
881      if (dfb_config->font_format == DSPF_A1 ||
882                dfb_config->font_format == DSPF_A1_LSB ||
883                dfb_config->font_format == DSPF_ARGB1555 ||
884                dfb_config->font_format == DSPF_RGBA5551)
885           load_mono = true;
886 
887      if (desc->flags & DFDESC_ATTRIBUTES) {
888           if (desc->attributes & DFFA_NOHINTING)
889                load_flags |= FT_LOAD_NO_HINTING;
890           if (desc->attributes & DFFA_NOBITMAP)
891                load_flags |= FT_LOAD_NO_BITMAP;
892           if (desc->attributes & DFFA_AUTOHINTING)
893                load_flags |= FT_LOAD_FORCE_AUTOHINT;
894           if (desc->attributes & DFFA_SOFTHINTING)
895                load_flags |= FT_LOAD_TARGET_LIGHT;
896           if (desc->attributes & DFFA_NOCHARMAP)
897                disable_charmap = true;
898           if (desc->attributes & DFFA_NOKERNING)
899                disable_kerning = true;
900           if (desc->attributes & DFFA_MONOCHROME)
901                load_mono = true;
902      }
903 
904      if (load_mono)
905           load_flags |= FT_LOAD_TARGET_MONO;
906 
907      if (!disable_charmap) {
908           pthread_mutex_lock ( &library_mutex );
909           err = FT_Select_Charmap( face, ft_encoding_unicode );
910           pthread_mutex_unlock ( &library_mutex );
911 
912 #if FREETYPE_MINOR > 0
913 
914           /* ft_encoding_latin_1 has been introduced in freetype-2.1 */
915           if (err) {
916                D_DEBUG( "DirectFB/FontFT2: "
917                         "Couldn't select Unicode encoding, "
918                         "falling back to Latin1.\n");
919                pthread_mutex_lock ( &library_mutex );
920                err = FT_Select_Charmap( face, ft_encoding_latin_1 );
921                pthread_mutex_unlock ( &library_mutex );
922           }
923 #endif
924           if (err) {
925                D_DEBUG( "DirectFB/FontFT2: "
926                         "Couldn't select Unicode/Latin1 encoding, "
927                         "trying Symbol.\n");
928                pthread_mutex_lock ( &library_mutex );
929                err = FT_Select_Charmap( face, ft_encoding_symbol );
930                pthread_mutex_unlock ( &library_mutex );
931 
932                if (!err)
933                     mask = 0xf000;
934           }
935      }
936 
937 #if 0
938      if (err) {
939           D_ERROR( "DirectFB/FontFT2: "
940                     "Couldn't select a suitable encoding for face %d from font file `%s'!\n", (desc->flags & DFDESC_INDEX) ? desc->index : 0, filename );
941           pthread_mutex_lock ( &library_mutex );
942           FT_Done_Face( face );
943           pthread_mutex_unlock ( &library_mutex );
944           DIRECT_DEALLOCATE_INTERFACE( thiz );
945           return DFB_FAILURE;
946      }
947 #endif
948 
949      if (desc->flags & (DFDESC_HEIGHT       | DFDESC_WIDTH |
950                         DFDESC_FRACT_HEIGHT | DFDESC_FRACT_WIDTH))
951      {
952           int fw = 0, fh = 0;
953 
954           if (desc->flags & DFDESC_FRACT_HEIGHT)
955                fh = desc->fract_height;
956           else if (desc->flags & DFDESC_HEIGHT)
957                fh = desc->height << 6;
958 
959           if (desc->flags & DFDESC_FRACT_WIDTH)
960                fw = desc->fract_width;
961           else if (desc->flags & DFDESC_WIDTH)
962                fw = desc->width << 6;
963 
964           pthread_mutex_lock ( &library_mutex );
965           err = FT_Set_Char_Size( face, fw, fh, 0, 0 );
966           pthread_mutex_unlock ( &library_mutex );
967           if (err) {
968                D_ERROR( "DirectB/FontFT2: "
969                          "Could not set pixel size to %d x %d!\n",
970                          (desc->flags & DFDESC_WIDTH)  ? desc->width  : 0,
971                          (desc->flags & DFDESC_HEIGHT) ? desc->height : 0 );
972                pthread_mutex_lock ( &library_mutex );
973                FT_Done_Face( face );
974                pthread_mutex_unlock ( &library_mutex );
975                DIRECT_DEALLOCATE_INTERFACE( thiz );
976                return DFB_FAILURE;
977           }
978      }
979 
980      face->generic.data = (void *)(unsigned long) load_flags;
981      face->generic.finalizer = NULL;
982 
983      ret = dfb_font_create( core, &font );
984      if (ret) {
985           pthread_mutex_lock ( &library_mutex );
986           FT_Done_Face( face );
987           pthread_mutex_unlock ( &library_mutex );
988           DIRECT_DEALLOCATE_INTERFACE( thiz );
989           return ret;
990      }
991 
992      D_ASSERT( font->pixel_format == DSPF_ARGB ||
993                font->pixel_format == DSPF_AiRGB ||
994                font->pixel_format == DSPF_ARGB8565 ||
995                font->pixel_format == DSPF_ARGB4444 ||
996                font->pixel_format == DSPF_RGBA4444 ||
997                font->pixel_format == DSPF_ARGB2554 ||
998                font->pixel_format == DSPF_ARGB1555 ||
999                font->pixel_format == DSPF_RGBA5551 ||
1000                font->pixel_format == DSPF_A8 ||
1001                font->pixel_format == DSPF_A4 ||
1002                font->pixel_format == DSPF_A1 ||
1003                font->pixel_format == DSPF_A1_LSB );
1004 
1005      font->ascender   = face->size->metrics.ascender >> 6;
1006      font->descender  = face->size->metrics.descender >> 6;
1007      font->height     = font->ascender + ABS(font->descender) + 1;
1008      font->maxadvance = face->size->metrics.max_advance >> 6;
1009 
1010      font->up_unit_x  = -sin_rot;
1011      font->up_unit_y  = -cos_rot;
1012 
1013      D_DEBUG( "DirectFB/FontFT2: height = %d, ascender = %d, descender = %d, maxadvance = %d, up unit: %5.2f,%5.2f\n",
1014               font->height, font->ascender, font->descender, font->maxadvance, font->up_unit_x, font->up_unit_y );
1015 
1016      font->GetGlyphData = get_glyph_info;
1017      font->RenderGlyph  = render_glyph;
1018 
1019      if (FT_HAS_KERNING(face) && !disable_kerning) {
1020           font->GetKerning = get_kerning;
1021           data = D_CALLOC( 1, sizeof(FT2ImplKerningData) );
1022      }
1023      else
1024           data = D_CALLOC( 1, sizeof(FT2ImplData) );
1025 
1026      data->face            = face;
1027      data->disable_charmap = disable_charmap;
1028 
1029      if (FT_HAS_KERNING(face) && !disable_kerning)
1030           init_kerning_cache( (FT2ImplKerningData*) data, font->up_unit_x, font->up_unit_y);
1031 
1032      if (desc->flags & DFDESC_FIXEDADVANCE) {
1033           data->fixed_advance = desc->fixed_advance;
1034           font->maxadvance    = desc->fixed_advance;
1035 
1036           if ((desc->flags & DFDESC_ATTRIBUTES) && (desc->attributes & DFFA_FIXEDCLIP))
1037                data->fixed_clip = true;
1038      }
1039 
1040      for (i=0; i<256; i++)
1041           data->indices[i] = FT_Get_Char_Index( face, i | mask );
1042 
1043      font->impl_data = data;
1044 
1045      dfb_font_register_encoding( font, "UTF8",   &ft2UTF8Funcs,   DTEID_UTF8 );
1046      dfb_font_register_encoding( font, "Latin1", &ft2Latin1Funcs, DTEID_OTHER );
1047 
1048      IDirectFBFont_Construct( thiz, font );
1049 
1050      thiz->Release = IDirectFBFont_FT2_Release;
1051 
1052      return DFB_OK;
1053 }
1054