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