📄 ftxkern.c
字号:
/******************************************************************* * * ftxkern.c 1.0 * * Kerning support extension. * * Copyright 1996-2002 by * David Turner, Robert Wilhelm, and Werner Lemberg. * * This file is part of the FreeType project, and may only be used * modified and distributed under the terms of the FreeType project * license, LICENSE.TXT. By continuing to use, modify, or distribute * this file you indicate that you have read the license and * understand and accept it fully. * * * The kerning support is currently part of the engine extensions. * ******************************************************************/#include "ftxkern.h"#include "ttextend.h"#include "tttypes.h"#include "ttdebug.h"#include "ttload.h"#include "ttmemory.h"#include "ttfile.h"#include "ttobjs.h"#include "tttags.h"/* Required by the tracing mode */#undef TT_COMPONENT#define TT_COMPONENT trace_any#define KERNING_ID Build_Extension_ID( 'k', 'e', 'r', 'n' )#undef KERN_INDEX#define KERN_INDEX(g1,g2) (((TT_ULong)g1 << 16) | g2) /* compare two kerning pairs, for sorting */ static int compare_kern_pairs( const void* a, const void* b ) { TT_Kern_0_Pair* pair1 = (TT_Kern_0_Pair*)a; TT_Kern_0_Pair* pair2 = (TT_Kern_0_Pair*)b; TT_ULong index1 = KERN_INDEX( pair1->left, pair1->right ); TT_ULong index2 = KERN_INDEX( pair2->left, pair2->right ); return ( index1 < index2 ? -1 : ( index1 > index2 ? 1 : 0 )); } /* a simple shell sort algorithm to avoid calling qsort */ /* (since this creates problems on 16-bit machines) */ static void sort_kern_pairs( TT_Kern_0_Pair* pairs, int count ) { TT_Kern_0_Pair *i, *j, *limit = pairs + count; TT_Kern_0_Pair temp; int gap; /* compute initial gap */ for ( gap = 0; ++gap < count; gap *= 3 ) ; while ( gap /= 3 ) { for ( i = pairs + gap; i < limit; i++ ) { for ( j = i - gap; ; j -= gap ) { TT_Kern_0_Pair* k = j + gap; if ( compare_kern_pairs( j, k ) < 0 ) break; temp = *j; *j = *k; *k = temp; if ( j < pairs + gap ) break; } } } } /* check whether the kern table is sorted */ static int is_sorted( TT_Kern_0_Pair* table, TT_ULong num_pairs ) { TT_ULong i; for ( i=1; i<num_pairs; i++ ) { if ( compare_kern_pairs(&table[i-1], &table[i]) != -1 ) return 0; } return 1; }/******************************************************************* * * Function : SubTable_Load_0 * * Description : Loads a format 0 kerning subtable data. * * Input : kern0 pointer to the kerning subtable * * Output : error code * * Notes : - Assumes that the stream is already `used' * * - the file cursor must be set by the caller * * - in case of error, the function _must_ destroy * the data it allocates! * ******************************************************************/ static TT_Error Subtable_Load_0( TT_Kern_0* kern0, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort num_pairs, n; if ( ACCESS_Frame( 8L ) ) return error; num_pairs = GET_UShort(); kern0->nPairs = 0; kern0->searchRange = GET_UShort(); kern0->entrySelector = GET_UShort(); kern0->rangeShift = GET_UShort(); /* we only set kern0->nPairs if the subtable has been loaded */ FORGET_Frame(); if ( ALLOC_ARRAY( kern0->pairs, num_pairs, TT_Kern_0_Pair ) ) return error; if ( ACCESS_Frame( num_pairs * 6L ) ) goto Fail; for ( n = 0; n < num_pairs; n++ ) { kern0->pairs[n].left = GET_UShort(); kern0->pairs[n].right = GET_UShort(); kern0->pairs[n].value = GET_UShort(); if ( kern0->pairs[n].left >= input->numGlyphs || kern0->pairs[n].right >= input->numGlyphs ) { FORGET_Frame(); error = TT_Err_Invalid_Kerning_Table; goto Fail; } } FORGET_Frame(); /* we're ok, set the pairs count */ kern0->nPairs = num_pairs; /* the spec says that the kerning pairs must be sorted, but some brain damaged font producers don't do that correctly.. (JvR 3/4/2000) */ if ( !is_sorted( kern0->pairs, num_pairs ) ) sort_kern_pairs( kern0->pairs, num_pairs ); return TT_Err_Ok; Fail: FREE( kern0->pairs ); return error; }/******************************************************************* * * Function : SubTable_Load_2 * * Description : Loads a format 2 kerning subtable data. * * Input : kern2 pointer to the kerning subtable * length subtable length. This is required as * the subheader doesn't give any indication * of the size of the `array' table. * * Output : error code * * Notes : - Assumes that the stream is already `used' * * - the file cursor must be set by the caller * * - in case of error, the function _must_ destroy * the data it allocates! * ******************************************************************/ static TT_Error Subtable_Load_2( TT_Kern_2* kern2, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); Long table_base; UShort left_offset, right_offset, array_offset; ULong array_size; UShort left_max, right_max, n; /* record the table offset */ table_base = FILE_Pos(); if ( ACCESS_Frame( 8L ) ) return error; kern2->rowWidth = GET_UShort(); left_offset = GET_UShort(); right_offset = GET_UShort(); array_offset = GET_UShort(); FORGET_Frame(); /* first load left and right glyph classes */ if ( FILE_Seek( table_base + left_offset ) || ACCESS_Frame( 4L ) ) return error; kern2->leftClass.firstGlyph = GET_UShort(); kern2->leftClass.nGlyphs = GET_UShort(); FORGET_Frame(); if ( ALLOC_ARRAY( kern2->leftClass.classes, kern2->leftClass.nGlyphs, UShort ) ) return error; /* load left offsets */ if ( ACCESS_Frame( kern2->leftClass.nGlyphs * 2L ) ) goto Fail_Left; for ( n = 0; n < kern2->leftClass.nGlyphs; n++ ) kern2->leftClass.classes[n] = GET_UShort(); FORGET_Frame(); /* right class */ if ( FILE_Seek( table_base + right_offset ) || ACCESS_Frame( 4L ) ) goto Fail_Left; kern2->rightClass.firstGlyph = GET_UShort(); kern2->rightClass.nGlyphs = GET_UShort(); FORGET_Frame(); if ( ALLOC_ARRAY( kern2->rightClass.classes, kern2->rightClass.nGlyphs, UShort ) ) goto Fail_Left; /* load right offsets */ if ( ACCESS_Frame( kern2->rightClass.nGlyphs * 2L ) ) goto Fail_Right; for ( n = 0; n < kern2->rightClass.nGlyphs; n++ ) kern2->rightClass.classes[n] = GET_UShort(); FORGET_Frame(); /* Now load the kerning array. We don't have its size, we */ /* must compute it from what we know. */ /* We thus compute the maximum left and right offsets and */ /* add them to get the array size. */ left_max = right_max = 0; for ( n = 0; n < kern2->leftClass.nGlyphs; n++ ) left_max = MAX( left_max, kern2->leftClass.classes[n] ); for ( n = 0; n < kern2->rightClass.nGlyphs; n++ ) right_max = MAX( right_max, kern2->leftClass.classes[n] ); array_size = left_max + right_max + 2; if ( ALLOC( kern2->array, array_size ) ) goto Fail_Right; if ( ACCESS_Frame( array_size ) ) goto Fail_Array; for ( n = 0; (UInt)n < array_size/2; n++ ) kern2->array[n] = GET_Short(); FORGET_Frame(); /* we're good now */ return TT_Err_Ok; Fail_Array: FREE( kern2->array );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -