pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ FT_UInt glyph1, FT_UInt glyph2, FT_Vector* kerning ) { PFR_Face face = (PFR_Face)pfrface; FT_Error error = PFR_Err_Ok; PFR_PhyFont phy_font = &face->phy_font; PFR_KernPair pairs = phy_font->kern_pairs; FT_UInt32 idx = PFR_KERN_INDEX( glyph1, glyph2 ); FT_UInt min, max; kerning->x = 0; kerning->y = 0; min = 0; max = phy_font->num_kern_pairs; while ( min < max ) { FT_UInt mid = ( min + max ) >> 1; PFR_KernPair pair = pairs + mid; FT_UInt32 pidx = PFR_KERN_PAIR_INDEX( pair ); if ( pidx == idx ) { kerning->x = pair->kerning; break; } if ( pidx < idx ) min = mid + 1; else max = mid; } return error; }
pfr_extra_item_load_kerning_pairs( FT_Byte* p, FT_Byte* limit, PFR_PhyFont phy_font ) { PFR_KernItem item = NULL; FT_Error error = FT_Err_Ok; FT_Memory memory = phy_font->memory; if ( FT_NEW( item ) ) goto Exit; PFR_CHECK( 4 ); item->pair_count = PFR_NEXT_BYTE( p ); item->base_adj = PFR_NEXT_SHORT( p ); item->flags = PFR_NEXT_BYTE( p ); item->offset = phy_font->offset + (FT_Offset)( p - phy_font->cursor ); #ifndef PFR_CONFIG_NO_CHECKS item->pair_size = 3; if ( item->flags & PFR_KERN_2BYTE_CHAR ) item->pair_size += 2; if ( item->flags & PFR_KERN_2BYTE_ADJ ) item->pair_size += 1; PFR_CHECK( item->pair_count * item->pair_size ); #endif /* load first and last pairs into the item to speed up */ /* lookup later... */ if ( item->pair_count > 0 ) { FT_UInt char1, char2; FT_Byte* q; if ( item->flags & PFR_KERN_2BYTE_CHAR ) { q = p; char1 = PFR_NEXT_USHORT( q ); char2 = PFR_NEXT_USHORT( q ); item->pair1 = PFR_KERN_INDEX( char1, char2 ); q = p + item->pair_size * ( item->pair_count - 1 ); char1 = PFR_NEXT_USHORT( q ); char2 = PFR_NEXT_USHORT( q ); item->pair2 = PFR_KERN_INDEX( char1, char2 ); } else { q = p; char1 = PFR_NEXT_BYTE( q ); char2 = PFR_NEXT_BYTE( q ); item->pair1 = PFR_KERN_INDEX( char1, char2 ); q = p + item->pair_size * ( item->pair_count - 1 ); char1 = PFR_NEXT_BYTE( q ); char2 = PFR_NEXT_BYTE( q ); item->pair2 = PFR_KERN_INDEX( char1, char2 ); } /* add new item to the current list */ item->next = NULL; *phy_font->kern_items_tail = item; phy_font->kern_items_tail = &item->next; phy_font->num_kern_pairs += item->pair_count; } else { /* empty item! */ FT_FREE( item ); } Exit: return error; Too_Short: FT_FREE( item ); error = FT_THROW( Invalid_Table ); FT_ERROR(( "pfr_extra_item_load_kerning_pairs:" " invalid kerning pairs table\n" )); goto Exit; }
pfr_face_get_kerning( FT_Face pfrface, /* PFR_Face */ FT_UInt glyph1, FT_UInt glyph2, FT_Vector* kerning ) { PFR_Face face = (PFR_Face)pfrface; FT_Error error = FT_Err_Ok; PFR_PhyFont phy_font = &face->phy_font; FT_UInt32 code1, code2, pair; kerning->x = 0; kerning->y = 0; if ( glyph1 > 0 ) glyph1--; if ( glyph2 > 0 ) glyph2--; /* convert glyph indices to character codes */ if ( glyph1 > phy_font->num_chars || glyph2 > phy_font->num_chars ) goto Exit; code1 = phy_font->chars[glyph1].char_code; code2 = phy_font->chars[glyph2].char_code; pair = PFR_KERN_INDEX( code1, code2 ); /* now search the list of kerning items */ { PFR_KernItem item = phy_font->kern_items; FT_Stream stream = pfrface->stream; for ( ; item; item = item->next ) { if ( pair >= item->pair1 && pair <= item->pair2 ) goto FoundPair; } goto Exit; FoundPair: /* we found an item, now parse it and find the value if any */ if ( FT_STREAM_SEEK( item->offset ) || FT_FRAME_ENTER( item->pair_count * item->pair_size ) ) goto Exit; { FT_UInt count = item->pair_count; FT_UInt size = item->pair_size; FT_UInt power = 1 << FT_MSB( count ); FT_UInt probe = power * size; FT_UInt extra = count - power; FT_Byte* base = stream->cursor; FT_Bool twobytes = FT_BOOL( item->flags & 1 ); FT_Bool twobyte_adj = FT_BOOL( item->flags & 2 ); FT_Byte* p; FT_UInt32 cpair; if ( extra > 0 ) { p = base + extra * size; if ( twobytes ) cpair = FT_NEXT_ULONG( p ); else cpair = PFR_NEXT_KPAIR( p ); if ( cpair == pair ) goto Found; if ( cpair < pair ) { if ( twobyte_adj ) p += 2; else p++; base = p; } } while ( probe > size ) { probe >>= 1; p = base + probe; if ( twobytes ) cpair = FT_NEXT_ULONG( p ); else cpair = PFR_NEXT_KPAIR( p ); if ( cpair == pair ) goto Found; if ( cpair < pair ) base += probe; } p = base; if ( twobytes ) cpair = FT_NEXT_ULONG( p ); else cpair = PFR_NEXT_KPAIR( p ); if ( cpair == pair ) { FT_Int value; Found: if ( twobyte_adj ) value = FT_PEEK_SHORT( p ); else value = p[0]; kerning->x = item->base_adj + value; } } FT_FRAME_EXIT(); } Exit: return error; }
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; }