/* (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Hundt , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef SIZEOF_LONG #include #include FT_GLYPH_H #ifndef FT_LOAD_TARGET_MONO /* FT_LOAD_TARGET_MONO was added in FreeType-2.1.3, we have to use (less good) FT_LOAD_MONOCHROME with older versions. Make it an alias for code simplicity. */ #define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME #endif static DFBResult Probe( IDirectFBFont_ProbeContext *ctx ); static DFBResult Construct( IDirectFBFont *thiz, CoreDFB *core, IDirectFBFont_ProbeContext *ctx, DFBFontDescription *desc ); #include DIRECT_INTERFACE_IMPLEMENTATION( IDirectFBFont, FT2 ) static FT_Library library = NULL; static int library_ref_count = 0; static pthread_mutex_t library_mutex = PTHREAD_MUTEX_INITIALIZER; #define KERNING_CACHE_MIN 0 #define KERNING_CACHE_MAX 127 #define KERNING_CACHE_SIZE (KERNING_CACHE_MAX - KERNING_CACHE_MIN + 1) #define KERNING_DO_CACHE(a,b) ((a) >= KERNING_CACHE_MIN && \ (a) <= KERNING_CACHE_MAX && \ (b) >= KERNING_CACHE_MIN && \ (b) <= KERNING_CACHE_MAX) #define KERNING_CACHE_ENTRY(a,b) \ (data->kerning[(a)-KERNING_CACHE_MIN][(b)-KERNING_CACHE_MIN]) #define CHAR_INDEX(c) (((c) < 256) ? data->indices[c] : FT_Get_Char_Index( data->face, c )) typedef struct { FT_Face face; int disable_charmap; int fixed_advance; bool fixed_clip; unsigned int indices[256]; } FT2ImplData; typedef struct { signed char x; signed char y; } KerningCacheEntry; typedef struct { FT2ImplData base; KerningCacheEntry kerning[KERNING_CACHE_SIZE][KERNING_CACHE_SIZE]; } FT2ImplKerningData; /**********************************************************************************************************************/ static DFBResult ft2UTF8GetCharacterIndex( CoreFont *thiz, unsigned int character, unsigned int *ret_index ) { FT2ImplData *data = thiz->impl_data; D_MAGIC_ASSERT( thiz, CoreFont ); if (data->disable_charmap) *ret_index = character; else { pthread_mutex_lock ( &library_mutex ); *ret_index = CHAR_INDEX( character ); pthread_mutex_unlock ( &library_mutex ); } return DFB_OK; } static DFBResult ft2UTF8DecodeText( CoreFont *thiz, const void *text, int length, unsigned int *ret_indices, int *ret_num ) { int pos = 0, num = 0; const u8 *bytes = text; FT2ImplData *data = thiz->impl_data; D_MAGIC_ASSERT( thiz, CoreFont ); D_ASSERT( text != NULL ); D_ASSERT( length >= 0 ); D_ASSERT( ret_indices != NULL ); D_ASSERT( ret_num != NULL ); pthread_mutex_lock ( &library_mutex ); while (pos < length) { unsigned int c; if (bytes[pos] < 128) c = bytes[pos++]; else { c = DIRECT_UTF8_GET_CHAR( &bytes[pos] ); pos += DIRECT_UTF8_SKIP(bytes[pos]); } if (data->disable_charmap) ret_indices[num++] = c; else ret_indices[num++] = CHAR_INDEX( c ); } pthread_mutex_unlock ( &library_mutex ); *ret_num = num; return DFB_OK; } static const CoreFontEncodingFuncs ft2UTF8Funcs = { .GetCharacterIndex = ft2UTF8GetCharacterIndex, .DecodeText = ft2UTF8DecodeText, }; /**********************************************************************************************************************/ static DFBResult ft2Latin1GetCharacterIndex( CoreFont *thiz, unsigned int character, unsigned int *ret_index ) { FT2ImplData *data = thiz->impl_data; D_MAGIC_ASSERT( thiz, CoreFont ); if (data->disable_charmap) *ret_index = character; else *ret_index = data->indices[character]; return DFB_OK; } static DFBResult ft2Latin1DecodeText( CoreFont *thiz, const void *text, int length, unsigned int *ret_indices, int *ret_num ) { int i; const u8 *bytes = text; FT2ImplData *data = thiz->impl_data; D_MAGIC_ASSERT( thiz, CoreFont ); D_ASSERT( text != NULL ); D_ASSERT( length >= 0 ); D_ASSERT( ret_indices != NULL ); D_ASSERT( ret_num != NULL ); if (data->disable_charmap) { for (i=0; iindices[bytes[i]]; } *ret_num = length; return DFB_OK; } static const CoreFontEncodingFuncs ft2Latin1Funcs = { .GetCharacterIndex = ft2Latin1GetCharacterIndex, .DecodeText = ft2Latin1DecodeText, }; /**********************************************************************************************************************/ static DFBResult render_glyph( CoreFont *thiz, unsigned int index, CoreGlyphData *info ) { FT_Error err; FT_Face face; FT_Int load_flags; u8 *src; int y; FT2ImplData *data = thiz->impl_data; CoreSurface *surface = info->surface; CoreSurfaceBufferLock lock; pthread_mutex_lock ( &library_mutex ); face = data->face; load_flags = (unsigned long) face->generic.data; load_flags |= FT_LOAD_RENDER; if ((err = FT_Load_Glyph( face, index, load_flags ))) { D_DEBUG( "DirectFB/FontFT2: Could not render glyph for character index #%d!\n", index ); pthread_mutex_unlock ( &library_mutex ); return DFB_FAILURE; } pthread_mutex_unlock ( &library_mutex ); err = dfb_surface_lock_buffer( surface, CSBR_BACK, CSAID_CPU, CSAF_WRITE, &lock ); if (err) { D_DERROR( err, "DirectFB/FontFT2: Unable to lock surface!\n" ); return err; } info->width = face->glyph->bitmap.width; if (info->width + info->start > surface->config.size.w) info->width = surface->config.size.w - info->start; info->height = face->glyph->bitmap.rows; if (info->height > surface->config.size.h) info->height = surface->config.size.h; /* bitmap_left and bitmap_top are relative to the glyph's origin on the baseline. info->left and info->top are relative to the top-left of the character cell. */ info->left = face->glyph->bitmap_left - thiz->ascender*thiz->up_unit_x; info->top = - face->glyph->bitmap_top - thiz->ascender*thiz->up_unit_y; if (data->fixed_clip) { while (info->left + info->width > data->fixed_advance) info->left--; if (info->left < 0) info->left = 0; if (info->width > data->fixed_advance) info->width = data->fixed_advance; } src = face->glyph->bitmap.buffer; lock.addr += DFB_BYTES_PER_LINE(surface->config.format, info->start); for (y=0; y < info->height; y++) { int i, j, n; u8 *dst8 = lock.addr; u16 *dst16 = lock.addr; u32 *dst32 = lock.addr; switch (face->glyph->bitmap.pixel_mode) { case ft_pixel_mode_grays: switch (surface->config.format) { case DSPF_ARGB: if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) { for (i=0; iwidth; i++) dst32[i] = src[i] * 0x01010101; } else for (i=0; iwidth; i++) dst32[i] = (src[i] << 24) | 0xFFFFFF; break; case DSPF_AiRGB: for (i=0; iwidth; i++) dst32[i] = ((src[i] ^ 0xFF) << 24) | 0xFFFFFF; break; case DSPF_ARGB4444: case DSPF_RGBA4444: if (thiz->surface_caps & DSCAPS_PREMULTIPLIED) { for (i=0; iwidth; i++) dst16[i] = (src[i] >> 4) * 0x1111; } else { if( surface->config.format == DSPF_ARGB4444 ) { for (i=0; iwidth; i++) dst16[i] = (src[i] << 8) | 0x0FFF; } else { for (i=0; iwidth; i++) dst16[i] = (src[i] >> 4) | 0xFFF0; } } break; case DSPF_ARGB2554: for (i=0; iwidth; i++) dst16[i] = (src[i] << 8) | 0x3FFF; break; case DSPF_ARGB1555: for (i=0; iwidth; i++) dst16[i] = (src[i] << 8) | 0x7FFF; break; case DSPF_A8: direct_memcpy( lock.addr, src, info->width ); break; case DSPF_A4: for (i=0, j=0; iwidth; i+=2, j++) dst8[j] = (src[i] & 0xF0) | (src[i+1] >> 4); break; case DSPF_A1: for (i=0, j=0; i < info->width; ++j) { register u8 p = 0; for (n=0; n<8 && iwidth; ++i, ++n) p |= (src[i] & 0x80) >> n; dst8[j] = p; } break; case DSPF_LUT2: for (i=0, j=0; i < info->width; ++j) { register u8 p = 0; for (n=0; n<8 && iwidth; ++i, n+=2) p |= (src[i] & 0xC0) >> n; dst8[j] = p; } break; default: D_UNIMPLEMENTED(); break; } break; case ft_pixel_mode_mono: switch (surface->config.format) { case DSPF_ARGB: for (i=0; iwidth; i++) dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0xFF : 0x00) << 24) | 0xFFFFFF; break; case DSPF_AiRGB: for (i=0; iwidth; i++) dst32[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0x00 : 0xFF) << 24) | 0xFFFFFF; break; case DSPF_ARGB4444: for (i=0; iwidth; i++) dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0xF : 0x0) << 12) | 0xFFF; break; case DSPF_RGBA4444: for (i=0; iwidth; i++) dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0xF : 0x0) ) | 0xFFF0; break; case DSPF_ARGB2554: for (i=0; iwidth; i++) dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0x3 : 0x0) << 14) | 0x3FFF; break; case DSPF_ARGB1555: for (i=0; iwidth; i++) dst16[i] = (((src[i>>3] & (1<<(7-(i%8)))) ? 0x1 : 0x0) << 15) | 0x7FFF; break; case DSPF_A8: for (i=0; iwidth; i++) dst8[i] = (src[i>>3] & (1<<(7-(i%8)))) ? 0xFF : 0x00; break; case DSPF_A4: for (i=0, j=0; iwidth; i+=2, j++) dst8[j] = ((src[i>>3] & (1<<(7-(i%8)))) ? 0xF0 : 0x00) | ((src[(i+1)>>3] & (1<<(7-((i+1)%8)))) ? 0x0F : 0x00); break; case DSPF_A1: direct_memcpy( lock.addr, src, DFB_BYTES_PER_LINE(DSPF_A1, info->width) ); break; default: D_UNIMPLEMENTED(); break; } break; default: break; } src += face->glyph->bitmap.pitch; lock.addr += lock.pitch; } dfb_surface_unlock_buffer( surface, &lock ); return DFB_OK; } static DFBResult get_glyph_info( CoreFont *thiz, unsigned int index, CoreGlyphData *info ) { FT_Error err; FT_Face face; FT_Int load_flags; FT2ImplData *data = (FT2ImplData*) thiz->impl_data; pthread_mutex_lock ( &library_mutex ); face = data->face; load_flags = (unsigned long) face->generic.data; if ((err = FT_Load_Glyph( face, index, load_flags ))) { D_DEBUG( "DirectFB/FontFT2: Could not load glyph for character index #%d!\n", index ); pthread_mutex_unlock ( &library_mutex ); return DFB_FAILURE; } if (face->glyph->format != ft_glyph_format_bitmap) { err = FT_Render_Glyph( face->glyph, (load_flags & FT_LOAD_TARGET_MONO) ? ft_render_mode_mono : ft_render_mode_normal ); if (err) { D_ERROR( "DirectFB/FontFT2: Could not render glyph for character index #%d!\n", index ); pthread_mutex_unlock ( &library_mutex ); return DFB_FAILURE; } } pthread_mutex_unlock ( &library_mutex ); info->width = face->glyph->bitmap.width; info->height = face->glyph->bitmap.rows; if (data->fixed_advance) { info->xadvance = - data->fixed_advance * thiz->up_unit_y; info->yadvance = data->fixed_advance * thiz->up_unit_x; } else { info->xadvance = face->glyph->advance.x >> 6; info->yadvance = - face->glyph->advance.y >> 6; } if (data->fixed_clip && info->width > data->fixed_advance) info->width = data->fixed_advance; return DFB_OK; } static DFBResult get_kerning( CoreFont *thiz, unsigned int prev, unsigned int current, int *kern_x, int *kern_y) { FT_Vector vector; FT2ImplKerningData *data = thiz->impl_data; KerningCacheEntry *cache = NULL; D_ASSUME( (kern_x != NULL) || (kern_y != NULL) ); /* * Use cached values if characters are in the * cachable range and the cache entry is already filled. */ if (KERNING_DO_CACHE (prev, current)) { cache = &KERNING_CACHE_ENTRY (prev, current); if (kern_x) *kern_x = (int) cache->x; if (kern_y) *kern_y = (int) cache->y; return DFB_OK; } pthread_mutex_lock ( &library_mutex ); /* Lookup kerning values for the character pair. */ /* The vector returned by FreeType does not allow for any rotation. */ FT_Get_Kerning( data->base.face, prev, current, ft_kerning_default, &vector ); pthread_mutex_unlock ( &library_mutex ); /* Convert to integer. */ if (kern_x) *kern_x = (int)(- vector.x*thiz->up_unit_y + vector.y*thiz->up_unit_x) >> 6; if (kern_y) *kern_y = (int)( vector.y*thiz->up_unit_y + vector.x*thiz->up_unit_x) >> 6; return DFB_OK; } static void init_kerning_cache( FT2ImplKerningData *data, float up_unit_x, float up_unit_y ) { int a, b; pthread_mutex_lock ( &library_mutex ); for (a=KERNING_CACHE_MIN; a<=KERNING_CACHE_MAX; a++) { for (b=KERNING_CACHE_MIN; b<=KERNING_CACHE_MAX; b++) { FT_Vector vector; KerningCacheEntry *cache = &KERNING_CACHE_ENTRY( a, b ); /* Lookup kerning values for the character pair. */ FT_Get_Kerning( data->base.face, a, b, ft_kerning_default, &vector ); cache->x = (signed char) ((int)(- vector.x*up_unit_y + vector.y*up_unit_x) >> 6); cache->y = (signed char) ((int)( vector.y*up_unit_y + vector.x*up_unit_x) >> 6); } } pthread_mutex_unlock ( &library_mutex ); } static DFBResult init_freetype( void ) { FT_Error err; pthread_mutex_lock ( &library_mutex ); if (!library) { D_DEBUG( "DirectFB/FontFT2: Initializing the FreeType2 library.\n" ); err = FT_Init_FreeType( &library ); if (err) { D_ERROR( "DirectFB/FontFT2: " "Initialization of the FreeType2 library failed!\n" ); library = NULL; pthread_mutex_unlock( &library_mutex ); return DFB_FAILURE; } } library_ref_count++; pthread_mutex_unlock( &library_mutex ); return DFB_OK; } static void release_freetype( void ) { pthread_mutex_lock( &library_mutex ); if (library && --library_ref_count == 0) { D_DEBUG( "DirectFB/FontFT2: Releasing the FreeType2 library.\n" ); FT_Done_FreeType( library ); library = NULL; } pthread_mutex_unlock( &library_mutex ); } static void IDirectFBFont_FT2_Destruct( IDirectFBFont *thiz ) { IDirectFBFont_data *data = (IDirectFBFont_data*)thiz->priv; if (data->font->impl_data) { FT2ImplData *impl_data = (FT2ImplData*) data->font->impl_data; pthread_mutex_lock ( &library_mutex ); FT_Done_Face( impl_data->face ); pthread_mutex_unlock ( &library_mutex ); D_FREE( impl_data ); data->font->impl_data = NULL; } IDirectFBFont_Destruct( thiz ); release_freetype(); } static DirectResult IDirectFBFont_FT2_Release( IDirectFBFont *thiz ) { DIRECT_INTERFACE_GET_DATA(IDirectFBFont) if (--data->ref == 0) { IDirectFBFont_FT2_Destruct( thiz ); } return DFB_OK; } static DFBResult Probe( IDirectFBFont_ProbeContext *ctx ) { FT_Error err; FT_Face face; D_DEBUG( "DirectFB/FontFT2: Probe font `%s'.\n", ctx->filename ); if (!ctx->content) return DFB_UNSUPPORTED; if (init_freetype() != DFB_OK) { return DFB_FAILURE; } pthread_mutex_lock ( &library_mutex ); /* * This should be * err = FT_New...Face( library, ctx->filename, -1, NULL ); * but due to freetype bugs it doesn't work. */ err = FT_New_Memory_Face( library, ctx->content, ctx->content_size, 0, &face ); if (!err) FT_Done_Face( face ); pthread_mutex_unlock ( &library_mutex ); release_freetype(); return err ? DFB_UNSUPPORTED : DFB_OK; } static DFBResult Construct( IDirectFBFont *thiz, CoreDFB *core, IDirectFBFont_ProbeContext *ctx, DFBFontDescription *desc ) { int i; DFBResult ret; CoreFont *font; FT_Face face; FT_Error err; FT_Int load_flags = FT_LOAD_DEFAULT; FT2ImplData *data; bool disable_charmap = false; bool disable_kerning = false; bool load_mono = false; u32 mask = 0; unsigned int size = 0, size_read = 0; char *filename = ctx->filename; /* intended for printf only */ float sin_rot = 0.0; float cos_rot = 1.0; D_DEBUG( "DirectFB/FontFT2: " "Construct font from file `%s' (index %d) at pixel size %d x %d and rotation %d.\n", filename, (desc->flags & DFDESC_INDEX) ? desc->index : 0, (desc->flags & DFDESC_WIDTH) ? desc->width : 0, (desc->flags & DFDESC_HEIGHT) ? desc->height : 0, (desc->flags & DFDESC_ROTATION) ? desc->rotation : 0 ); if (init_freetype() != DFB_OK) { DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_FAILURE; } pthread_mutex_lock ( &library_mutex ); err = FT_New_Memory_Face( library, ctx->content, ctx->content_size, (desc->flags & DFDESC_INDEX) ? desc->index : 0, &face ); pthread_mutex_unlock ( &library_mutex ); if (err) { switch (err) { case FT_Err_Unknown_File_Format: D_ERROR( "DirectFB/FontFT2: " "Unsupported font format in file `%s'!\n", filename ); break; default: D_ERROR( "DirectFB/FontFT2: " "Failed loading face %d from font file `%s'!\n", (desc->flags & DFDESC_INDEX) ? desc->index : 0, filename ); break; } DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_FAILURE; } if ((desc->flags & DFDESC_ROTATION) && desc->rotation) { if (!FT_IS_SCALABLE(face)) { D_ERROR( "DirectFB/FontFT2: " "Face %d from font file `%s' is not scalable so cannot be rotated\n", (desc->flags & DFDESC_INDEX) ? desc->index : 0, filename ); pthread_mutex_lock ( &library_mutex ); FT_Done_Face( face ); pthread_mutex_unlock ( &library_mutex ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_UNSUPPORTED; } float rot_radians = 2.0 * M_PI * desc->rotation / (1<<24); sin_rot = sin(rot_radians); cos_rot = cos(rot_radians); int sin_rot_fx = (int)(sin_rot*65536.0); int cos_rot_fx = (int)(cos_rot*65536.0); FT_Matrix matrix; matrix.xx = cos_rot_fx; matrix.xy = -sin_rot_fx; matrix.yx = sin_rot_fx; matrix.yy = cos_rot_fx; pthread_mutex_lock ( &library_mutex ); FT_Set_Transform( face, &matrix, NULL ); /* FreeType docs suggest FT_Set_Transform returns an error code, but it seems that this is not the case. */ pthread_mutex_unlock ( &library_mutex ); } if (dfb_config->font_format == DSPF_A1 || dfb_config->font_format == DSPF_ARGB1555) load_mono = true; if (desc->flags & DFDESC_ATTRIBUTES) { if (desc->attributes & DFFA_NOHINTING) load_flags |= FT_LOAD_NO_HINTING; if (desc->attributes & DFFA_NOBITMAP) load_flags |= FT_LOAD_NO_BITMAP; if (desc->attributes & DFFA_NOCHARMAP) disable_charmap = true; if (desc->attributes & DFFA_NOKERNING) disable_kerning = true; if (desc->attributes & DFFA_MONOCHROME) load_mono = true; } if (load_mono) load_flags |= FT_LOAD_TARGET_MONO; if (!disable_charmap) { pthread_mutex_lock ( &library_mutex ); err = FT_Select_Charmap( face, ft_encoding_unicode ); pthread_mutex_unlock ( &library_mutex ); #if FREETYPE_MINOR > 0 /* ft_encoding_latin_1 has been introduced in freetype-2.1 */ if (err) { D_DEBUG( "DirectFB/FontFT2: " "Couldn't select Unicode encoding, " "falling back to Latin1.\n"); pthread_mutex_lock ( &library_mutex ); err = FT_Select_Charmap( face, ft_encoding_latin_1 ); pthread_mutex_unlock ( &library_mutex ); } #endif if (err) { D_DEBUG( "DirectFB/FontFT2: " "Couldn't select Unicode/Latin1 encoding, " "trying Symbol.\n"); pthread_mutex_lock ( &library_mutex ); err = FT_Select_Charmap( face, ft_encoding_symbol ); pthread_mutex_unlock ( &library_mutex ); if (!err) mask = 0xf000; } } #if 0 if (err) { D_ERROR( "DirectFB/FontFT2: " "Couldn't select a suitable encoding for face %d from font file `%s'!\n", (desc->flags & DFDESC_INDEX) ? desc->index : 0, filename ); pthread_mutex_lock ( &library_mutex ); FT_Done_Face( face ); pthread_mutex_unlock ( &library_mutex ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_FAILURE; } #endif if (desc->flags & (DFDESC_HEIGHT | DFDESC_WIDTH | DFDESC_FRACT_HEIGHT | DFDESC_FRACT_WIDTH)) { int fw = 0, fh = 0; if (desc->flags & DFDESC_FRACT_HEIGHT) fh = desc->fract_height; else if (desc->flags & DFDESC_HEIGHT) fh = desc->height << 6; if (desc->flags & DFDESC_FRACT_WIDTH) fw = desc->fract_width; else if (desc->flags & DFDESC_WIDTH) fw = desc->width << 6; pthread_mutex_lock ( &library_mutex ); err = FT_Set_Char_Size( face, fw, fh, 0, 0 ); pthread_mutex_unlock ( &library_mutex ); if (err) { D_ERROR( "DirectB/FontFT2: " "Could not set pixel size to %d x %d!\n", (desc->flags & DFDESC_WIDTH) ? desc->width : 0, (desc->flags & DFDESC_HEIGHT) ? desc->height : 0 ); pthread_mutex_lock ( &library_mutex ); FT_Done_Face( face ); pthread_mutex_unlock ( &library_mutex ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return DFB_FAILURE; } } face->generic.data = (void *)(unsigned long) load_flags; face->generic.finalizer = NULL; ret = dfb_font_create( core, desc, filename, &font ); if (ret) { pthread_mutex_lock ( &library_mutex ); FT_Done_Face( face ); pthread_mutex_unlock ( &library_mutex ); DIRECT_DEALLOCATE_INTERFACE( thiz ); return ret; } D_ASSERT( font->pixel_format == DSPF_ARGB || font->pixel_format == DSPF_AiRGB || font->pixel_format == DSPF_ARGB4444 || font->pixel_format == DSPF_RGBA4444 || font->pixel_format == DSPF_ARGB2554 || font->pixel_format == DSPF_ARGB1555 || font->pixel_format == DSPF_A8 || font->pixel_format == DSPF_A4 || font->pixel_format == DSPF_A1 ); font->ascender = face->size->metrics.ascender >> 6; font->descender = face->size->metrics.descender >> 6; font->height = font->ascender + ABS(font->descender) + 1; font->maxadvance = face->size->metrics.max_advance >> 6; font->up_unit_x = -sin_rot; font->up_unit_y = -cos_rot; D_DEBUG( "DirectFB/FontFT2: height = %d, ascender = %d, descender = %d, maxadvance = %d, up unit: %5.2f,%5.2f\n", font->height, font->ascender, font->descender, font->maxadvance, font->up_unit_x, font->up_unit_y ); font->GetGlyphData = get_glyph_info; font->RenderGlyph = render_glyph; if (FT_HAS_KERNING(face) && !disable_kerning) { font->GetKerning = get_kerning; data = D_CALLOC( 1, sizeof(FT2ImplKerningData) ); } else data = D_CALLOC( 1, sizeof(FT2ImplData) ); data->face = face; data->disable_charmap = disable_charmap; if (FT_HAS_KERNING(face) && !disable_kerning) init_kerning_cache( (FT2ImplKerningData*) data, font->up_unit_x, font->up_unit_y); if (desc->flags & DFDESC_FIXEDADVANCE) { data->fixed_advance = desc->fixed_advance; font->maxadvance = desc->fixed_advance; if ((desc->flags & DFDESC_ATTRIBUTES) && (desc->attributes & DFFA_FIXEDCLIP)) data->fixed_clip = true; } for (i=0; i<256; i++) data->indices[i] = FT_Get_Char_Index( face, i | mask ); font->impl_data = data; dfb_font_register_encoding( font, "UTF8", &ft2UTF8Funcs, DTEID_UTF8 ); dfb_font_register_encoding( font, "Latin1", &ft2Latin1Funcs, DTEID_OTHER ); IDirectFBFont_Construct( thiz, font ); thiz->Release = IDirectFBFont_FT2_Release; return DFB_OK; }