pfr_face_get_kerning( PFR_Face face, FT_UInt glyph1, FT_UInt glyph2, FT_Vector* kerning ) { FT_Error error; PFR_PhyFont phy_font = &face->phy_font; PFR_KernItem item = phy_font->kern_items; FT_UInt32 idx = PFR_KERN_INDEX( glyph1, glyph2 ); kerning->x = 0; kerning->y = 0; /* find the kerning item containing our pair */ while ( item ) { if ( item->pair1 <= idx && idx <= item->pair2 ) goto Found_Item; item = item->next; } /* not found */ goto Exit; Found_Item: { /* perform simply binary search within the item */ FT_UInt min, mid, max; FT_Stream stream = face->root.stream; FT_Byte* p; if ( FT_STREAM_SEEK( item->offset ) || FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) goto Exit; min = 0; max = item->pair_count; while ( min < max ) { FT_UInt char1, char2, charcode; mid = ( min + max ) >> 1; p = stream->cursor + mid*item->pair_size; if ( item->flags & PFR_KERN_2BYTE_CHAR ) { char1 = FT_NEXT_USHORT( p ); char2 = FT_NEXT_USHORT( p ); } else { char1 = FT_NEXT_USHORT( p ); char2 = FT_NEXT_USHORT( p ); } charcode = PFR_KERN_INDEX( char1, char2 ); if ( idx == charcode ) { if ( item->flags & PFR_KERN_2BYTE_ADJ ) kerning->x = item->base_adj + FT_NEXT_SHORT( p ); else kerning->x = item->base_adj + FT_NEXT_CHAR( p ); break; } if ( idx > charcode ) min = mid + 1; else max = mid; } FT_FRAME_EXIT(); } Exit: return 0; }
static FT_Error pfr_sort_kerning_pairs( FT_Stream stream, PFR_PhyFont phy_font ) { FT_Error error; FT_Memory memory = stream->memory; PFR_KernPair pairs; PFR_KernItem item; PFR_Char chars = phy_font->chars; FT_UInt num_chars = phy_font->num_chars; FT_UInt count; /* create kerning pairs array */ if ( FT_NEW_ARRAY( phy_font->kern_pairs, phy_font->num_kern_pairs ) ) goto Exit; /* load all kerning items into the array, * converting character codes into glyph indices */ pairs = phy_font->kern_pairs; item = phy_font->kern_items; count = 0; for ( ; item; item = item->next ) { FT_UInt limit = count + item->pair_count; FT_Byte* p; if ( limit > phy_font->num_kern_pairs ) { error = PFR_Err_Invalid_Table; goto Exit; } if ( FT_STREAM_SEEK( item->offset ) || FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) goto Exit; p = stream->cursor; for ( ; count < limit; count++ ) { PFR_KernPair pair = pairs + count; FT_UInt char1, char2; FT_Int kerning; if ( item->flags & PFR_KERN_2BYTE_CHAR ) { char1 = FT_NEXT_USHORT( p ); char2 = FT_NEXT_USHORT( p ); } else { char1 = FT_NEXT_BYTE( p ); char2 = FT_NEXT_BYTE( p ); } if ( item->flags & PFR_KERN_2BYTE_ADJ ) kerning = item->base_adj + FT_NEXT_SHORT( p ); else kerning = item->base_adj + FT_NEXT_CHAR( p ); pair->glyph1 = pfr_get_gindex( chars, num_chars, char1 ); pair->glyph2 = pfr_get_gindex( chars, num_chars, char2 ); pair->kerning = kerning; } FT_FRAME_EXIT(); } /* sort the resulting array */ ft_qsort( pairs, count, sizeof ( PFR_KernPairRec ), pfr_compare_kern_pairs ); Exit: if ( error ) { /* disable kerning data in case of error */ phy_font->num_kern_pairs = 0; } return error; }