📄 ttcmap.c
字号:
static void
tt_cmap4_reset( TT_CMap4 cmap,
FT_UInt code,
FT_UInt range_index )
{
if ( tt_cmap4_set_range( cmap, range_index ) >= 0 )
{
cmap->cur_charcode = code;
tt_cmap4_next( cmap );
}
}
#endif /* OPT_CMAP4 */
FT_CALLBACK_DEF( FT_Error )
tt_cmap4_validate( FT_Byte* table,
FT_Validator valid )
{
FT_Byte* p = table + 2; /* skip format */
FT_UInt length = TT_NEXT_USHORT( p );
FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids;
FT_UInt num_segs;
FT_Error error = SFNT_Err_Ok;
/* in certain fonts, the `length' field is invalid and goes */
/* out of bound. We try to correct this here... */
if ( length < 16 )
FT_INVALID_TOO_SHORT;
if ( table + length > valid->limit )
{
if ( valid->level >= FT_VALIDATE_TIGHT )
FT_INVALID_TOO_SHORT;
length = (FT_UInt)( valid->limit - table );
}
p = table + 6;
num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */
if ( valid->level >= FT_VALIDATE_PARANOID )
{
/* check that we have an even value here */
if ( num_segs & 1 )
FT_INVALID_DATA;
}
num_segs /= 2;
/* check the search parameters - even though we never use them */
/* */
if ( valid->level >= FT_VALIDATE_PARANOID )
{
/* check the values of 'searchRange', 'entrySelector', 'rangeShift' */
FT_UInt search_range = TT_NEXT_USHORT( p );
FT_UInt entry_selector = TT_NEXT_USHORT( p );
FT_UInt range_shift = TT_NEXT_USHORT( p );
if ( ( search_range | range_shift ) & 1 ) /* must be even values */
FT_INVALID_DATA;
search_range /= 2;
range_shift /= 2;
/* `search range' is the greatest power of 2 that is <= num_segs */
if ( search_range > num_segs ||
search_range * 2 < num_segs ||
search_range + range_shift != num_segs ||
search_range != ( 1U << entry_selector ) )
FT_INVALID_DATA;
}
ends = table + 14;
starts = table + 16 + num_segs * 2;
deltas = starts + num_segs * 2;
offsets = deltas + num_segs * 2;
glyph_ids = offsets + num_segs * 2;
if ( glyph_ids > table + length )
FT_INVALID_TOO_SHORT;
/* check last segment, its end count must be FFFF */
if ( valid->level >= FT_VALIDATE_PARANOID )
{
p = ends + ( num_segs - 1 ) * 2;
if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
FT_INVALID_DATA;
}
/* check that segments are sorted in increasing order and do not */
/* overlap; check also the offsets */
{
FT_UInt start, end, last = 0, offset, n;
FT_Int delta;
for ( n = 0; n < num_segs; n++ )
{
p = starts + n * 2;
start = TT_PEEK_USHORT( p );
p = ends + n * 2;
end = TT_PEEK_USHORT( p );
p = deltas + n * 2;
delta = TT_PEEK_SHORT( p );
p = offsets + n * 2;
offset = TT_PEEK_USHORT( p );
if ( start > end )
FT_INVALID_DATA;
/* this test should be performed at default validation level; */
/* unfortunately, some popular Asian fonts present overlapping */
/* ranges in their charmaps */
/* */
if ( n > 0 && start <= last )
{
if ( valid->level >= FT_VALIDATE_TIGHT )
FT_INVALID_DATA;
else
error = SFNT_Err_Invalid_CharMap_Format;
}
if ( offset && offset != 0xFFFFU )
{
p += offset; /* start of glyph id array */
/* check that we point within the glyph ids table only */
if ( valid->level >= FT_VALIDATE_TIGHT )
{
if ( p < glyph_ids ||
p + ( end - start + 1 ) * 2 > table + length )
FT_INVALID_DATA;
}
else
{
if ( p < glyph_ids ||
p + ( end - start + 1 ) * 2 > valid->limit )
FT_INVALID_DATA;
}
/* check glyph indices within the segment range */
if ( valid->level >= FT_VALIDATE_TIGHT )
{
FT_UInt i, idx;
for ( i = start; i < end; i++ )
{
idx = FT_NEXT_USHORT( p );
if ( idx != 0 )
{
idx = (FT_UInt)( idx + delta ) & 0xFFFFU;
if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
FT_INVALID_GLYPH_ID;
}
}
}
}
else if ( offset == 0xFFFFU )
{
/* Some fonts (erroneously?) use a range offset of 0xFFFF */
/* to mean missing glyph in cmap table */
/* */
if ( valid->level >= FT_VALIDATE_PARANOID ||
n != num_segs - 1 ||
!( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) )
FT_INVALID_DATA;
}
last = end;
}
}
return error;
}
FT_CALLBACK_DEF( FT_UInt )
tt_cmap4_char_index( TT_CMap cmap,
FT_UInt32 char_code )
{
FT_Byte* table = cmap->data;
FT_UInt result = 0;
if ( char_code < 0x10000UL )
{
FT_UInt idx, num_segs2;
FT_Int delta;
FT_UInt code = (FT_UInt)char_code;
FT_Byte* p;
p = table + 6;
num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); /* be paranoid! */
if ( !cmap->unsorted )
{
/* Some fonts have more than 170 segments in their charmaps! */
/* We changed this function to use a more efficient binary */
/* search for improving performance */
FT_UInt min = 0;
FT_UInt max = num_segs2 >> 1;
FT_UInt mid, start, end, offset;
while ( min < max )
{
mid = ( min + max ) >> 1;
p = table + 14 + mid * 2;
end = TT_NEXT_USHORT( p );
p += num_segs2;
start = TT_PEEK_USHORT( p);
if ( code < start )
max = mid;
else if ( code > end )
min = mid + 1;
else
{
/* we found the segment */
idx = code;
p += num_segs2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
if ( offset == 0xFFFFU )
goto Exit;
if ( offset != 0 )
{
p += offset + 2 * ( idx - start );
idx = TT_PEEK_USHORT( p );
}
if ( idx != 0 )
result = (FT_UInt)( idx + delta ) & 0xFFFFU;
goto Exit;
}
}
}
else
{
FT_UInt n;
FT_Byte* q;
p = table + 14; /* ends table */
q = table + 16 + num_segs2; /* starts table */
for ( n = 0; n < num_segs2; n += 2 )
{
FT_UInt end = TT_NEXT_USHORT( p );
FT_UInt start = TT_NEXT_USHORT( q );
FT_UInt offset;
if ( code < start )
break;
if ( code <= end )
{
idx = code;
p = q + num_segs2 - 2;
delta = TT_PEEK_SHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
if ( offset == 0xFFFFU )
goto Exit;
if ( offset != 0 )
{
p += offset + 2 * ( idx - start );
idx = TT_PEEK_USHORT( p );
}
if ( idx != 0 )
result = (FT_UInt)( idx + delta ) & 0xFFFFU;
}
}
}
}
Exit:
return result;
}
FT_CALLBACK_DEF( FT_UInt )
tt_cmap4_char_next( TT_CMap cmap,
FT_UInt32 *pchar_code )
{
FT_Byte* table = cmap->data;
FT_UInt32 result = 0;
FT_UInt gindex = 0;
FT_UInt32 char_code = *pchar_code;
FT_Byte* p;
FT_UInt code, num_segs2;
if ( char_code >= 0xFFFFUL )
goto Exit;
#ifdef OPT_CMAP4
{
TT_CMap4 cmap4 = (TT_CMap4)cmap;
if ( char_code == cmap4->old_charcode )
{
result = cmap4->cur_charcode;
gindex = cmap4->cur_gindex;
if ( result != 0 )
{
tt_cmap4_next( cmap4 );
goto Exit;
}
}
}
#endif /* OPT_CMAP4 */
code = (FT_UInt)char_code + 1;
p = table + 6;
num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); /* ensure even-ness */
if ( !cmap->unsorted )
{
for (;;)
{
/* Some fonts have more than 170 segments in their charmaps! */
/* We changed this function to use a more efficient binary */
/* search */
FT_UInt offset;
FT_Int delta;
FT_UInt min = 0;
FT_UInt max = num_segs2 >> 1;
FT_UInt mid, start, end;
FT_UInt hi;
/* we begin by finding the segment which end is
closer to our code point */
hi = max + 1;
while ( min < max )
{
mid = ( min + max ) >> 1;
p = table + 14 + mid * 2;
end = TT_PEEK_USHORT( p );
if ( end < code )
min = mid + 1;
else
{
hi = mid;
max = mid;
}
}
if ( hi > max )
{
/* the point is behind the last segment;
we will exit right now */
goto Exit;
}
p = table + 14 + hi * 2;
end = TT_PEEK_USHORT( p );
p += 2 + num_segs2;
start = TT_PEEK_USHORT( p );
if ( code < start )
code = start;
p += num_segs2;
delta = TT_PEEK_USHORT( p );
p += num_segs2;
offset = TT_PEEK_USHORT( p );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -